* [edk2-platforms][PATCH V1 01/15] Platform/Loongson: Add Serial Port library
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 02/15] Platform/Loongson: Support SEC And Add Readme.md xianglai
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Serial Port library for LoongarchQemuPkg
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LoongArchQemuPkg/Include/Library/Cpu.h | 344 ++++++++++
.../Include/LoongArchQemuPlatform.h | 103 +++
.../Library/SerialPortLib/SerialPortLib.c | 614 ++++++++++++++++++
.../Library/SerialPortLib/SerialPortLib.inf | 36 +
4 files changed, 1097 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
new file mode 100644
index 0000000000..de466b7c6f
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Cpu.h
@@ -0,0 +1,344 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - EXC - Exception
+ - INT - Interrupt
+ - FPU - Floating Point Unit
+ - CSR - CPU Status Register
+ - READQ - Read Quad Word
+**/
+#ifndef LOONGARCH_CPU_H_
+#define LOONGARCH_CPU_H_
+
+/* Exception types decoded by machdep exception decoder */
+#define EXC_INT 0 /* HW interrupt */
+#define EXC_TLBL 1 /* TLB miss on a load */
+#define EXC_TLBS 2 /* TLB miss on a store */
+#define EXC_TLBI 3 /* TLB miss on a ifetch */
+#define EXC_TLBM 4 /* TLB modified fault */
+#define EXC_TLBRI 5 /* TLB Read-Inhibit exception */
+#define EXC_TLBXI 6 /* TLB Execution-Inhibit exception */
+#define EXC_TLBPE 7 /* TLB Privilege Error */
+#define EXC_ADE 8 /* Address Error */
+#define EXC_ALE 9 /* Unalign Access */
+#define EXC_OOB 10 /* Out of bounds */
+#define EXC_SYS 11 /* System call */
+#define EXC_BP 12 /* Breakpoint */
+#define EXC_INE 13 /* Inst. Not Exist */
+#define EXC_IPE 14 /* Inst. Privileged Error */
+#define EXC_FPDIS 15 /* FPU Disabled */
+#define EXC_LSXDIS 16 /* LSX Disabled */
+#define EXC_LASXDIS 17 /* LASX Disabled */
+#define EXC_FPE 18 /* Floating Point Exception */
+#define EXC_WATCH 19 /* Watch address reference */
+#define EXC_BAD 255 /* Undecodeable */
+
+#define COPY_SIGCODE // copy sigcode above user stack in exec
+#define ZERO $r0 /* wired zero */
+#define RA $r1 /* return address */
+#define GP $r2 /* global pointer - caller saved for PIC */
+#define SP $r3 /* stack pointer */
+#define V0 $r4 /* return value - caller saved */
+#define V1 $r5
+#define A0 $r4 /* argument registers */
+#define A1 $r5
+#define A2 $r6
+#define A3 $r7
+#define A4 $r8 /* arg reg 64 bit; caller saved in 32 bit */
+#define A5 $r9
+#define A6 $r10
+#define A7 $r11
+#define T0 $r12 /* caller saved */
+#define T1 $r13
+#define T2 $r14
+#define T3 $r15
+#define T4 $r16 /* callee saved */
+#define T5 $r17
+#define T6 $r18
+#define T7 $r19
+#define T8 $r20 /* caller saved */
+#define TP $r21 /* TLS */
+#define FP $r22 /* frame pointer */
+#define S0 $r23 /* callee saved */
+#define S1 $r24
+#define S2 $r25
+#define S3 $r26
+#define S4 $r27
+#define S5 $r28
+#define S6 $r29
+#define S7 $r30
+#define S8 $r31 /* callee saved */
+
+#define FCSR0 $r0
+
+//
+// Location of the saved registers relative to ZERO.
+// Usage is p->p_regs[XX].
+//
+#define RA_NUM 1
+#define GP_NUM 2
+#define SP_NUM 3
+#define A0_NUM 4
+#define A1_NUM 5
+#define A2_NUM 6
+#define A3_NUM 7
+#define A4_NUM 8
+#define A5_NUM 9
+#define A6_NUM 10
+#define A7_NUM 11
+#define T0_NUM 12
+#define T1_NUM 13
+#define T2_NUM 14
+#define T3_NUM 15
+#define T4_NUM 16
+#define T5_NUM 17
+#define T6_NUM 18
+#define T7_NUM 19
+#define T8_NUM 20
+#define TP_NUM 21
+#define FP_NUM 22
+#define S0_NUM 23
+#define S1_NUM 24
+#define S2_NUM 25
+#define S3_NUM 26
+#define S4_NUM 27
+#define S5_NUM 28
+#define S6_NUM 29
+#define S7_NUM 30
+#define S8_NUM 31
+
+#define FP0_NUM 0
+#define FP1_NUM 1
+#define FP2_NUM 2
+#define FP3_NUM 3
+#define FP4_NUM 4
+#define FP5_NUM 5
+#define FP6_NUM 6
+#define FP7_NUM 7
+#define FP8_NUM 8
+#define FP9_NUM 9
+#define FP10_NUM 10
+#define FP11_NUM 11
+#define FP12_NUM 12
+#define FP13_NUM 13
+#define FP14_NUM 14
+#define FP15_NUM 15
+#define FP16_NUM 16
+#define FP17_NUM 17
+#define FP18_NUM 18
+#define FP19_NUM 19
+#define FP20_NUM 20
+#define FP21_NUM 21
+#define FP22_NUM 22
+#define FP23_NUM 23
+#define FP24_NUM 24
+#define FP25_NUM 25
+#define FP26_NUM 26
+#define FP27_NUM 27
+#define FP28_NUM 28
+#define FP29_NUM 29
+#define FP30_NUM 30
+#define FP31_NUM 31
+#define FCSR_NUM 32
+#define FCC_NUM 33
+
+#ifdef __ASSEMBLY__
+#define _ULCAST_
+#define _U64CAST_
+#else
+#define _ULCAST_ (unsigned long)
+#define _U64CAST_ (u64)
+#endif
+
+#define LOONGARCH_CSR_CRMD 0
+#define LOONGARCH_CSR_PRMD 1
+#define LOONGARCH_CSR_EUEN 2
+#define CSR_EUEN_LBTEN_SHIFT 3
+#define CSR_EUEN_LBTEN (_ULCAST_(0x1) << CSR_EUEN_LBTEN_SHIFT)
+#define CSR_EUEN_LASXEN_SHIFT 2
+#define CSR_EUEN_LASXEN (_ULCAST_(0x1) << CSR_EUEN_LASXEN_SHIFT)
+#define CSR_EUEN_LSXEN_SHIFT 1
+#define CSR_EUEN_LSXEN (_ULCAST_(0x1) << CSR_EUEN_LSXEN_SHIFT)
+#define CSR_EUEN_FPEN_SHIFT 0
+#define CSR_EUEN_FPEN (_ULCAST_(0x1) << CSR_EUEN_FPEN_SHIFT)
+#define LOONGARCH_CSR_ECFG 4
+
+/* Exception status */
+#define LOONGARCH_CSR_ESTAT 5
+#define CSR_ESTAT_ESUBCODE_SHIFT 22
+#define CSR_ESTAT_ESUBCODE_WIDTH 9
+#define CSR_ESTAT_ESUBCODE (_ULCAST_(0x1ff) << CSR_ESTAT_ESUBCODE_SHIFT)
+#define CSR_ESTAT_EXC_SHIFT 16
+#define CSR_ESTAT_EXC_WIDTH 6
+#define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT)
+#define CSR_ESTAT_IS_SHIFT 0
+#define CSR_ESTAT_IS_WIDTH 15
+#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT)
+#define LOONGARCH_CSR_EPC 6
+#define LOONGARCH_CSR_BADV 7
+#define LOONGARCH_CSR_BADINST 8
+#define LOONGARCH_CSR_BADI 8
+#define LOONGARCH_CSR_EBASE 0xc /* Exception entry base address */
+#define LOONGARCH_CSR_CPUNUM 0x20 /* CPU core number */
+
+/* register number save in stack on exception */
+#define FP_BASE_NUM 34
+#define BASE_NUM 32
+#define CSR_NUM 10
+#define FP_BASE_INDEX (CSR_NUM + BASE_NUM)
+#define BOOTCORE_ID 0
+
+#define LOONGSON_IOCSR_IPI_STATUS 0x1000
+#define LOONGSON_IOCSR_IPI_EN 0x1004
+#define LOONGSON_IOCSR_IPI_SET 0x1008
+#define LOONGSON_IOCSR_IPI_CLEAR 0x100c
+#define LOONGSON_CSR_MAIL_BUF0 0x1020
+#define LOONGSON_CSR_MAIL_BUF1 0x1028
+#define LOONGSON_CSR_MAIL_BUF2 0x1030
+#define LOONGSON_CSR_MAIL_BUF3 0x1038
+
+/* Bit Domains for CFG registers */
+#define LOONGARCH_CPUCFG4 0x4
+#define LOONGARCH_CPUCFG5 0x5
+
+/* Kscratch registers */
+#define LOONGARCH_CSR_KS0 0x30
+#define LOONGARCH_CSR_KS1 0x31
+
+/* Stable timer registers */
+#define LOONGARCH_CSR_TMCFG 0x41
+#define LOONGARCH_CSR_TMCFG_EN (1ULL << 0)
+#define LOONGARCH_CSR_TMCFG_PERIOD (1ULL << 1)
+#define LOONGARCH_CSR_TMCFG_TIMEVAL (0x3fffffffffffULL << 2)
+#define LOONGARCH_CSR_TVAL 0x42 /* Timer value */
+#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */
+#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */
+
+/* TLB refill exception base address */
+#define LOONGARCH_CSR_TLBREBASE 0x88
+#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill exception */
+#define LOONGARCH_CSR_PGD 0x1b /* Page table base */
+
+/* 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 */
+
+/*
+ Reads data from the specified CSR register.
+
+ @param[OUT] val The value is read from the CSR specified register.
+ @param[IN] reg Specifies the register number of the CSR to read the data.
+
+ @retval VOID
+ */
+#define LOONGARCH_CSR_READQ(val, reg) \
+do { \
+ UINT64 __res; \
+ /* csrrd rd, csr_num */ \
+ __asm__ __volatile__( \
+ "csrrd %0, %1 \n\t" \
+ :"=r"(__res) \
+ :"i"(reg) \
+ : \
+ ); \
+ (val) = __res; \
+} while(0)
+
+/*
+ Write data to the specified CSR register.
+
+ @param[OUT] val The value is write to the CSR specified register.
+ @param[IN] reg Specifies the register number of the CSR to write the data.
+
+ @retval VOID
+ */
+#define LOONGARCH_CSR_WRITEQ(val, reg) \
+do { \
+ UINT64 __val = val; \
+ /* csrwr rd, csr_num */ \
+ __asm__ __volatile__( \
+ "csrwr %0, %1 \n\t" \
+ : "+r"(__val) \
+ : "i"(reg), "r"(__val) \
+ : "memory" \
+ ); \
+} while(0)
+
+/*
+ Exchange specified bit data with the specified CSR registers
+
+ @param[IN] val The value Exchanged with the CSR specified register.
+ @param[IN] mask Specifies the mask for swapping bits
+ @param[IN] reg Specifies the register number of the CSR to Exchange the data.
+
+ @retval VOID
+ */
+#define LOONGARCH_CSR_XCHGQ(val, mask, reg) \
+do { \
+ UINT64 __val = val; \
+ UINT64 __mask = mask; \
+ /* csrwr rd, csr_num */ \
+ __asm__ __volatile__( \
+ "csrxchg %0, %1, %2 \n\t" \
+ : "+r"(__val) \
+ : "r"(__mask), "i"(reg), "r"(__val) \
+ : "memory" \
+ ); \
+} while(0)
+/*
+ Reads data from the specified CPUCFG register.
+
+ @param[OUT] val The value is read from the CPUCFG specified register.
+ @param[IN] reg Specifies the register number of the CPUCFG to read the data.
+
+ @retval VOID
+ */
+#define LOONGARCH_GET_CPUCFG(val, reg) \
+do { \
+ UINT64 __res; \
+ /* cpucfg rd, rj */ \
+ __asm__ __volatile__( \
+ "cpucfg %0, %1 \n\t" \
+ :"=r"(__res) \
+ :"r"(reg) \
+ : \
+ ); \
+ val = (UINT32)__res; \
+} while(0)
+
+/*
+ Enables floating-point unit
+
+ @param VOID
+
+ @retval VOID
+ */
+#define LOONGARCH_ENABLR_FPU() \
+do { \
+ LOONGARCH_CSR_XCHGQ(CSR_EUEN_FPEN, \
+ CSR_EUEN_FPEN, \
+ LOONGARCH_CSR_EUEN); \
+} while (0)
+
+/*
+ Disable floating-point unit
+
+ @param VOID
+
+ @retval VOID
+ */
+#define LOONGARCH_DISABLE_FPU() \
+do { \
+ LOONGARCH_CSR_XCHGQ(0, \
+ CSR_EUEN_FPEN, \
+ LOONGARCH_CSR_EUEN); \
+} while (0)
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
new file mode 100644
index 0000000000..62b81d88c3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchQemuPlatform.h
@@ -0,0 +1,103 @@
+/** @file
+ LoongArch Qemu Platform macro definition.
+
+ Copyright (c) 2021, Loongson Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#ifndef LOONGARCH_QEMU_PLATFORM_H_
+#define LOONGARCH_QEMU_PLATFORM_H_
+
+
+/* Acpi pm device */
+#define LS7A_PCH_REG_BASE 0x10000000UL
+#define LS7A_ACPI_REG_BASE (LS7A_PCH_REG_BASE + 0x000D0000)
+#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */
+#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */
+
+#define ACPI_BITMASK_SLEEP_TYPE 0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE 0x2000
+
+
+//---------------------------------------------
+// UART Register Offsets
+//---------------------------------------------
+#define BAUD_LOW_OFFSET 0x00
+#define BAUD_HIGH_OFFSET 0x01
+#define IER_OFFSET 0x01
+#define LCR_SHADOW_OFFSET 0x01
+#define FCR_SHADOW_OFFSET 0x02
+#define IR_CONTROL_OFFSET 0x02
+#define FCR_OFFSET 0x02
+#define EIR_OFFSET 0x02
+#define BSR_OFFSET 0x03
+#define LCR_OFFSET 0x03
+#define MCR_OFFSET 0x04
+#define LSR_OFFSET 0x05
+#define MSR_OFFSET 0x06
+
+/* character format control register */
+#define CFCR_DLAB 0x80 /* divisor latch */
+#define CFCR_SBREAK 0x40 /* send break */
+#define CFCR_PZERO 0x30 /* zero parity */
+#define CFCR_PONE 0x20 /* one parity */
+#define CFCR_PEVEN 0x10 /* even parity */
+#define CFCR_PODD 0x00 /* odd parity */
+#define CFCR_PENAB 0x08 /* parity enable */
+#define CFCR_STOPB 0x04 /* 2 stop bits */
+#define CFCR_8BITS 0x03 /* 8 data bits */
+#define CFCR_7BITS 0x02 /* 7 data bits */
+#define CFCR_6BITS 0x01 /* 6 data bits */
+#define CFCR_5BITS 0x00 /* 5 data bits */
+/* modem control register */
+#define MCR_LOOPBACK 0x10 /* loopback */
+#define MCR_IENABLE 0x08 /* output 2 = int enable */
+#define MCR_DRS 0x04 /* output 1 = xxx */
+#define MCR_RTS 0x02 /* enable RTS */
+#define MCR_DTR 0x01 /* enable DTR */
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80 /* error in receive fifo */
+#define LSR_TSRE 0x40 /* transmitter empty */
+#define LSR_TXRDY 0x20 /* transmitter ready */
+#define LSR_BI 0x10 /* break detected */
+#define LSR_FE 0x08 /* framing error */
+#define LSR_PE 0x04 /* parity error */
+#define LSR_OE 0x02 /* overrun error */
+#define LSR_RXRDY 0x01 /* receiver ready */
+#define LSR_RCV_MASK 0x1f
+
+/* 16550 UART register offsets and bitfields */
+#define R_UART_RXBUF 0
+#define R_UART_TXBUF 0
+#define R_UART_BAUD_LOW 0
+#define R_UART_BAUD_HIGH 1
+#define R_UART_FCR 2
+#define B_UART_FCR_FIFOE BIT0
+#define B_UART_FCR_FIFO64 BIT5
+#define R_UART_LCR 3
+#define B_UART_LCR_DLAB BIT7
+#define R_UART_MCR 4
+#define B_UART_MCR_DTRC BIT0
+#define B_UART_MCR_RTS BIT1
+#define R_UART_LSR 5
+#define B_UART_LSR_RXRDY BIT0
+#define B_UART_LSR_TXRDY BIT5
+#define B_UART_LSR_TEMT BIT6
+#define R_UART_MSR 6
+#define B_UART_MSR_CTS BIT4
+#define B_UART_MSR_DSR BIT5
+#define B_UART_MSR_RI BIT6
+#define B_UART_MSR_DCD BIT7
+#define UART_BASE_ADDRESS (0x1fe001e0)
+#define UART_BPS (115200)
+#define UART_WAIT_TIMOUT (1000000)
+//---------------------------------------------
+// UART Settings
+//---------------------------------------------
+#define PHYS_TO_CACHED(x) ((x))
+#define PHYS_TO_UNCACHED(x) ((x))
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
new file mode 100644
index 0000000000..766e606be5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.c
@@ -0,0 +1,614 @@
+/** @file
+ UART Serial Port library functions
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Bps - Bit Per Second
+ - CTL - Control
+ - Config - Configure
+**/
+
+#include <Base.h>
+#include <Library/Cpu.h>
+#include <Library/IoLib.h>
+#include <Library/SerialPortLib.h>
+#include <LoongArchQemuPlatform.h>
+
+UINTN gUartBase = PHYS_TO_UNCACHED(UART_BASE_ADDRESS);
+UINTN gBps = UART_BPS;
+
+/**
+ Initialize the serial device hardware.
+
+ If no initialization is required, then return RETURN_SUCCESS.
+ If the serial device was successfuly initialized, then return RETURN_SUCCESS.
+ If the serial device could not be initialized, then return RETURN_DEVICE_ERROR.
+
+ @retval RETURN_SUCCESS The serial device was initialized.
+ @retval RETURN_DEVICE_ERROR The serail device could not be initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortInitialize (
+ VOID
+ )
+{
+ UINTN TimeOut;
+ //
+ // wait for Tx fifo to completely drain */
+ //
+ TimeOut = UART_WAIT_TIMOUT;
+ while (!(MmioRead8 ((UINTN) gUartBase + LSR_OFFSET) & LSR_TSRE)) {
+ if (--TimeOut == 0) {
+ break;
+ }
+ }
+ //
+ // Set communications format
+ //
+ MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_DLAB);
+
+ //
+ // Configure baud rate
+ //
+
+
+ MmioWrite8 ((UINTN) (gUartBase + LCR_OFFSET), CFCR_8BITS);
+ MmioWrite8 ((UINTN) (gUartBase + MCR_OFFSET), MCR_IENABLE | MCR_DTR | MCR_RTS);
+ //
+ // if enable interrupt the kernel of lemote will error in STR mode during wake up phase.
+ //
+ //MmioWrite8 ((UINTN) (gUartBase + IER_OFFSET), CFCR_8BITS);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Write data from buffer to serial device.
+
+ Writes NumberOfBytes data bytes from Buffer to the serial device.
+ The number of bytes actually written to the serial device is returned.
+ If the return value is less than NumberOfBytes, then the write operation failed.
+
+ If Buffer is NULL, then ASSERT ().
+
+ If NumberOfBytes is zero, then return 0.
+
+ @param Buffer Pointer to the data buffer to be written.
+ @param NumberOfBytes Number of bytes to written to the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes written to the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+UartCtlWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN CtlAddr
+)
+{
+ UINTN Result;
+ UINT8 Data;
+
+ if (Buffer == NULL) {
+ return 0;
+ }
+
+ Result = NumberOfBytes;
+
+ while (NumberOfBytes--) {
+ //
+ // Wait for the serail port to be ready.
+ //
+ do {
+ Data = MmioRead8 (CtlAddr + LSR_OFFSET);
+ } while ((Data & LSR_TXRDY) == 0);
+ MmioWrite8 (CtlAddr, *Buffer++);
+ }
+
+ return Result;
+}
+/**
+ Writes data to serial port.
+
+ @param Buffer Pointer to the data buffer to store the data writed to serial port.
+ @param NumberOfBytes Number of bytes to write to the serial port.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes write the serial port.
+ If this value is less than NumberOfBytes, then the write operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortWrite (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ return UartCtlWrite (Buffer, NumberOfBytes, gUartBase);
+}
+/**
+ Reads data from a serial device into a buffer.
+
+ @param Buffer Pointer to the data buffer to store the data read from the serial device.
+ @param NumberOfBytes Number of bytes to read from the serial device.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes read from the serial device.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+UartCtlRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes,
+ IN UINTN CtlAddr
+)
+{
+ UINTN Result;
+ UINT8 Data;
+
+ if (NULL == Buffer) {
+ return 0;
+ }
+
+ Result = NumberOfBytes;
+
+ while (NumberOfBytes--) {
+ //
+ // Wait for the serail port to be ready.
+ //
+ do {
+ Data = MmioRead8 (CtlAddr + LSR_OFFSET);
+ } while ((Data & LSR_RXRDY) == 0);
+
+ *Buffer++ = MmioRead8 (CtlAddr);
+ }
+
+ return Result;
+}
+/**
+ Read data from serial port.
+
+ @param Buffer Pointer to the data buffer to store the data read from serial port.
+ @param NumberOfBytes Number of bytes to read from the serial port.
+
+ @retval 0 NumberOfBytes is 0.
+ @retval >0 The number of bytes read from the serial port.
+ If this value is less than NumberOfBytes, then the read operation failed.
+
+**/
+UINTN
+EFIAPI
+SerialPortRead (
+ OUT UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+)
+{
+ return UartCtlRead (Buffer, NumberOfBytes, gUartBase);
+}
+/**
+ Polls a serial device to see if there is any data waiting to be read.
+
+ Polls aserial device to see if there is any data waiting to be read.
+ If there is data waiting to be read from the serial device, then TRUE is returned.
+ If there is no data waiting to be read from the serial device, then FALSE is returned.
+
+ @retval TRUE Data is waiting to be read from the serial device.
+ @retval FALSE There is no data waiting to be read from the serial device.
+
+**/
+BOOLEAN
+EFIAPI
+SerialPortPoll (
+ VOID
+ )
+{
+ UINT8 Data;
+
+ //
+ // Read the serial port status.
+ //
+ Data = MmioRead8 ((UINTN) gUartBase + LSR_OFFSET);
+
+ return (BOOLEAN) ((Data & LSR_RXRDY) != 0);
+}
+/**
+ To get serial register base address.
+
+ @param VOID
+
+ @return serial register base address.
+**/
+UINTN
+GetSerialRegisterBase (
+ VOID
+ )
+{
+ return gUartBase;
+}
+/**
+ Read an 8-bit register.
+ @param Base The base address register of UART device.
+ @param Offset The offset of the register to read.
+
+ @return The value read from the 16550 register.
+
+**/
+UINT8
+SerialPortReadRegister (
+ UINTN Base,
+ UINTN Offset
+ )
+{
+ return MmioRead8 (Base + Offset);
+}
+
+/**
+ Write an 8-bit register.
+ @param Base The base address register of UART device.
+ @param Offset The offset of the register to write.
+ @param Value The value to write to the register specified by Offset.
+
+ @return The value written to the 16550 register.
+
+**/
+UINT8
+SerialPortWriteRegister (
+ UINTN Base,
+ UINTN Offset,
+ UINT8 Value
+ )
+{
+ return MmioWrite8 (Base + Offset, Value);
+}
+
+
+
+/**
+ Sets the control bits on a serial device.
+
+ @param Control Sets the bits of Control that are settable.
+
+ @retval RETURN_SUCCESS The new control bits were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetControl (
+ IN UINT32 Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Mcr;
+
+ //
+ // First determine the parameter is invalid.
+ //
+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0)
+ {
+ return RETURN_UNSUPPORTED;
+ }
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+ Mcr &= (~(B_UART_MCR_DTRC | B_UART_MCR_RTS));
+
+ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
+ Mcr |= B_UART_MCR_DTRC;
+ }
+
+ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
+ Mcr |= B_UART_MCR_RTS;
+ }
+
+ //
+ // Write the Modem Control Register.
+ //
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_MCR, Mcr);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Retrieve the status of the control bits on a serial device.
+
+ @param Control A pointer to return the current control signals from the serial device.
+
+ @retval RETURN_SUCCESS The control bits were read from the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortGetControl (
+ OUT UINT32 *Control
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Msr;
+ UINT8 Mcr;
+ UINT8 Lsr;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ *Control = 0;
+
+ //
+ // Read the Modem Status Register.
+ //
+ Msr = SerialPortReadRegister (SerialRegisterBase, R_UART_MSR);
+
+ if ((Msr & B_UART_MSR_CTS) == B_UART_MSR_CTS) {
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;
+ }
+
+ if ((Msr & B_UART_MSR_DSR) == B_UART_MSR_DSR) {
+ *Control |= EFI_SERIAL_DATA_SET_READY;
+ }
+
+ if ((Msr & B_UART_MSR_RI) == B_UART_MSR_RI) {
+ *Control |= EFI_SERIAL_RING_INDICATE;
+ }
+
+ if ((Msr & B_UART_MSR_DCD) == B_UART_MSR_DCD) {
+ *Control |= EFI_SERIAL_CARRIER_DETECT;
+ }
+
+ //
+ // Read the Modem Control Register.
+ //
+ Mcr = SerialPortReadRegister (SerialRegisterBase, R_UART_MCR);
+
+ if ((Mcr & B_UART_MCR_DTRC) == B_UART_MCR_DTRC) {
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
+ }
+
+ if ((Mcr & B_UART_MCR_RTS) == B_UART_MCR_RTS) {
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;
+ }
+
+ if (PcdGetBool (PcdSerialUseHardwareFlowControl)) {
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+
+ //
+ // Read the Line Status Register.
+ //
+ Lsr = SerialPortReadRegister (SerialRegisterBase, R_UART_LSR);
+
+ if ((Lsr & (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) == (B_UART_LSR_TEMT | B_UART_LSR_TXRDY)) {
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+ }
+
+ if ((Lsr & B_UART_LSR_RXRDY) == 0) {
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Sets the baud rate, receive FIFO depth, transmit/receice time out, parity,
+ data bits, and stop bits on a serial device.
+
+ @param BaudRate The requested baud rate. A BaudRate value of 0 will use the
+ device's default interface speed.
+ On output, the value actually set.
+ @param ReveiveFifoDepth The requested depth of the FIFO on the receive side of the
+ serial interface. A ReceiveFifoDepth value of 0 will use
+ the device's default FIFO depth.
+ On output, the value actually set.
+ @param Timeout The requested time out for a single character in microseconds.
+ This timeout applies to both the transmit and receive side of the
+ interface. A Timeout value of 0 will use the device's default time
+ out value.
+ On output, the value actually set.
+ @param Parity The type of parity to use on this serial device. A Parity value of
+ DefaultParity will use the device's default parity value.
+ On output, the value actually set.
+ @param DataBits The number of data bits to use on the serial device. A DataBits
+ vaule of 0 will use the device's default data bit setting.
+ On output, the value actually set.
+ @param StopBits The number of stop bits to use on this serial device. A StopBits
+ value of DefaultStopBits will use the device's default number of
+ stop bits.
+ On output, the value actually set.
+
+ @retval RETURN_SUCCESS The new attributes were set on the serial device.
+ @retval RETURN_UNSUPPORTED The serial device does not support this operation.
+ @retval RETURN_INVALID_PARAMETER One or more of the attributes has an unsupported value.
+ @retval RETURN_DEVICE_ERROR The serial device is not functioning correctly.
+
+**/
+RETURN_STATUS
+EFIAPI
+UartCtlConfig (
+ IN OUT UINT64 *BaudRate,
+ IN OUT UINT32 *ReceiveFifoDepth,
+ IN OUT UINT32 *Timeout,
+ IN OUT EFI_PARITY_TYPE *Parity,
+ IN OUT UINT8 *DataBits,
+ IN OUT EFI_STOP_BITS_TYPE *StopBits,
+ IN UINTN CtlAddr
+ )
+{
+ UINTN SerialRegisterBase;
+ UINT8 Lcr;
+ UINT8 LcrData;
+ UINT8 LcrParity;
+ UINT8 LcrStop;
+
+
+ SerialRegisterBase = CtlAddr;
+ if (SerialRegisterBase ==0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ //
+ // Check for default settings and fill in actual values.
+ //
+ if (*BaudRate == 0) {
+ *BaudRate = PcdGet32 (PcdSerialBaudRate);
+ }
+
+ if (*DataBits == 0) {
+ LcrData = (UINT8) (PcdGet8 (PcdSerialLineControl) & 0x3);
+ *DataBits = LcrData + 5;
+ } else {
+ if ((*DataBits < 5)
+ || (*DataBits > 8))
+ {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Map 5..8 to 0..3
+ //
+ LcrData = (UINT8) (*DataBits - (UINT8) 5);
+ }
+
+ if (*Parity == DefaultParity) {
+ LcrParity = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 3) & 0x7);
+ switch (LcrParity) {
+ case 0:
+ *Parity = NoParity;
+ break;
+
+ case 3:
+ *Parity = EvenParity;
+ break;
+
+ case 1:
+ *Parity = OddParity;
+ break;
+
+ case 7:
+ *Parity = SpaceParity;
+ break;
+
+ case 5:
+ *Parity = MarkParity;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (*Parity) {
+ case NoParity:
+ LcrParity = 0;
+ break;
+
+ case EvenParity:
+ LcrParity = 3;
+ break;
+
+ case OddParity:
+ LcrParity = 1;
+ break;
+
+ case SpaceParity:
+ LcrParity = 7;
+ break;
+
+ case MarkParity:
+ LcrParity = 5;
+ break;
+
+ default:
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+
+ if (*StopBits == DefaultStopBits) {
+ LcrStop = (UINT8) ((PcdGet8 (PcdSerialLineControl) >> 2) & 0x1);
+ switch (LcrStop) {
+ case 0:
+ *StopBits = OneStopBit;
+ break;
+
+ case 1:
+ if (*DataBits == 5) {
+ *StopBits = OneFiveStopBits;
+ } else {
+ *StopBits = TwoStopBits;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ switch (*StopBits) {
+ case OneStopBit:
+ LcrStop = 0;
+ break;
+
+ case OneFiveStopBits:
+ case TwoStopBits:
+ LcrStop = 1;
+ break;
+
+ default:
+ return RETURN_INVALID_PARAMETER;
+ }
+ }
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, B_UART_LCR_DLAB);
+
+ //
+ // Clear DLAB and configure Data Bits, Parity, and Stop Bits.
+ // Strip reserved bits from line control value
+ //
+ Lcr = (UINT8) ((LcrParity << 3) | (LcrStop << 2) | LcrData);
+ SerialPortWriteRegister (SerialRegisterBase, R_UART_LCR, (UINT8) (Lcr & 0x3F));
+
+ return RETURN_SUCCESS;
+}
+/**
+ Set the serial port Attributes.
+
+ @param VOID
+
+ @return serial register base address.
+**/
+RETURN_STATUS
+EFIAPI
+SerialPortSetAttributes (
+ IN OUT UINT64 *BaudRate,
+ IN OUT UINT32 *ReceiveFifoDepth,
+ IN OUT UINT32 *Timeout,
+ IN OUT EFI_PARITY_TYPE *Parity,
+ IN OUT UINT8 *DataBits,
+ IN OUT EFI_STOP_BITS_TYPE *StopBits
+ )
+{
+ UINTN SerialRegisterBase;
+
+ SerialRegisterBase = GetSerialRegisterBase ();
+
+ return UartCtlConfig (&gBps, ReceiveFifoDepth, Timeout, Parity, DataBits, StopBits,
+ SerialRegisterBase);
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
new file mode 100644
index 0000000000..6c4674151b
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
@@ -0,0 +1,36 @@
+## @file
+# UART Serial Port library functions
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PcAtSerialPortLib
+ FILE_GUID = f4fb883d-8138-4f29-bb0c-c574e9312c74
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SerialPortLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ BaseLib
+ IoLib
+ PcdLib
+
+[Sources]
+ SerialPortLib.c
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseHardwareFlowControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate ## CONSUMES
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 02/15] Platform/Loongson: Support SEC And Add Readme.md
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 01/15] Platform/Loongson: Add Serial Port library xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Add SEC Code And Readme.md for LoongArchQemu
Signed-off-by: xianglai li <lixianglai@loongson.cn>
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Include/LoongArchAsmMacro.h | 23 +
.../Loongson/LoongArchQemuPkg/Loongson.dec | 38 ++
.../Loongson/LoongArchQemuPkg/Loongson.dsc | 133 +++++
.../Loongson/LoongArchQemuPkg/Loongson.fdf | 53 ++
.../LoongArchQemuPkg/Loongson.fdf.inc | 21 +
Platform/Loongson/LoongArchQemuPkg/Readme.md | 53 ++
.../LoongArchQemuPkg/Sec/LoongArch64/Start.S | 76 +++
.../Loongson/LoongArchQemuPkg/Sec/SecMain.c | 510 ++++++++++++++++++
.../Loongson/LoongArchQemuPkg/Sec/SecMain.inf | 49 ++
Readme.md | 9 +
10 files changed, 965 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/LoongArchAsmMacro.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dec
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Readme.md
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchAsmMacro.h b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchAsmMacro.h
new file mode 100644
index 0000000000..366d4308e8
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/LoongArchAsmMacro.h
@@ -0,0 +1,23 @@
+/** @file
+ LoongArch ASM macro definition.
+
+ Copyright (c) 2021, Loongson Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#ifndef LOONGARCH_ASM_MACRO_H_
+#define LOONGARCH_ASM_MACRO_H_
+
+#include <Base.h>
+
+#define _ASM_FUNC(Name, Section) \
+ .global Name ; \
+ .section #Section, "ax" ; \
+ .type Name, %function ; \
+ Name:
+
+#define ASM_FUNC(Name) _ASM_FUNC(ASM_PFX(Name), .text. ## Name)
+
+#endif // __LOONGARCH_ASM_MACRO_H__
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
new file mode 100644
index 0000000000..248b668fd1
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -0,0 +1,38 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = LoongArchQemuPkg
+ PACKAGE_GUID = b51d765a-41da-45fc-a537-de3ee785c0f6
+ PACKAGE_VERSION = 0.1
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+# Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+[Includes.common]
+ Include # Root include for the package
+
+[Guids]
+ gLoongArchQemuPkgTokenSpaceGuid = { 0x0e0383ce, 0x0151, 0x4d01, { 0x80, 0x0e, 0x3f, 0xef, 0x8b, 0x27, 0x6d, 0x52 } }
+
+[PcdsFixedAtBuild, PcdsDynamic]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000003
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000004
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize|0|UINT32|0x00000016
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|0|UINT32|0x00000017
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase|0|UINT64|0x0000001c
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize|0|UINT32|0x0000001d
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|0x0|UINT64|0x00000028
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize|0x0|UINT32|0x00000029
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
new file mode 100644
index 0000000000..f23fed77e6
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -0,0 +1,133 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+###############################################################################
+[Defines]
+ PLATFORM_NAME = LoongArchQemu
+ PLATFORMPKG_NAME = LoongArchQemu
+ PLATFORM_GUID = 7926ea52-b0dc-4ee8-ac63-341eebd84ed4
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME)
+ SUPPORTED_ARCHITECTURES = LOONGARCH64
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+ FLASH_DEFINITION = Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+ TTY_TERMINAL = FALSE
+
+############################################################################
+#
+# Defines for default states. These can be changed on the command line.
+# -D FLAG=VALUE
+############################################################################
+[BuildOptions]
+ GCC:RELEASE_*_*_CC_FLAGS = -DSPEEDUP
+
+ #
+ # Disable deprecated APIs.
+ #
+ GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
+
+[BuildOptions.LOONGARCH64.EDKII.SEC]
+ *_*_*_CC_FLAGS =
+
+#[BuildOptions.common.EDKII.DXE_CORE,BuildOptions.common.EDKII.DXE_DRIVER,BuildOptions.common.EDKII.UEFI_DRIVER,BuildOptions.common.EDKII.UEFI_APPLICATION]
+# GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000
+
+[BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
+ GCC:*_*_LOONGARCH64_DLINK_FLAGS = -z common-page-size=0x10000
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+
+!include MdePkg/MdeLibs.dsc.inc
+
+[LibraryClasses.common]
+ PcdLib | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ PrintLib | MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ BaseMemoryLib | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+
+
+ BaseLib | MdePkg/Library/BaseLib/BaseLib.inf
+ PeCoffLib | MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PeCoffGetEntryPointLib | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ IoLib | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ SerialPortLib | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
+ DebugPrintErrorLevelLib | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ PeCoffExtraActionLib | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+ DebugAgentLib | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+
+ DebugLib | MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+
+
+
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform.
+#
+################################################################################
+[PcdsFixedAtBuild]
+## BaseLib ##
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength | 1000000
+
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel | 0x8000004F
+ # DEBUG_INIT 0x00000001 // Initialization
+ # DEBUG_WARN 0x00000002 // Warnings
+ # DEBUG_LOAD 0x00000004 // Load events
+ # DEBUG_FS 0x00000008 // EFI File system
+ # DEBUG_POOL 0x00000010 // Alloc & Free (pool)
+ # DEBUG_PAGE 0x00000020 // Alloc & Free (page)
+ # DEBUG_INFO 0x00000040 // Informational debug messages
+ # DEBUG_DISPATCH 0x00000080 // PEI/DXE/SMM Dispatchers
+ # DEBUG_VARIABLE 0x00000100 // Variable
+ # DEBUG_BM 0x00000400 // Boot Manager
+ # DEBUG_BLKIO 0x00001000 // BlkIo Driver
+ # DEBUG_NET 0x00004000 // Network Io Driver
+ # DEBUG_UNDI 0x00010000 // UNDI Driver
+ # DEBUG_LOADFILE 0x00020000 // LoadFile
+ # DEBUG_EVENT 0x00080000 // Event messages
+ # DEBUG_GCD 0x00100000 // Global Coherency Database changes
+ # DEBUG_CACHE 0x00200000 // Memory range cachability changes
+ # DEBUG_VERBOSE 0x00400000 // Detailed debug messages that may
+ # DEBUG_ERROR 0x80000000 // Error
+
+!if $(TARGET) == RELEASE
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask | 0x21
+!else
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask | 0x2f
+!endif
+ # DEBUG_ASSERT_ENABLED 0x01
+ # DEBUG_PRINT_ENABLED 0x02
+ # DEBUG_CODE_ENABLED 0x04
+ # CLEAR_MEMORY_ENABLED 0x08
+ # ASSERT_BREAKPOINT_ENABLED 0x10
+ # ASSERT_DEADLOOP_ENABLED 0x20
+
+ gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress | 0x90000000
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize | 0x10000
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase | 0x90010000
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize | 0x10000
+
+
+[Components]
+
+ #
+ # SEC Phase modules
+ #
+ Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
new file mode 100644
index 0000000000..128b3843db
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -0,0 +1,53 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+#####################################################################################################
+[Defines]
+!include Loongson.fdf.inc
+
+#####################################################################################################
+[FD.QEMU_EFI]
+BaseAddress = $(FD_BASE_ADDRESS)
+Size = $(FD_SIZE)
+ErasePolarity = 1
+BlockSize = $(BLOCK_SIZE)
+NumBlocks = $(FD_BLOCKS)
+
+$(SECFV_OFFSET)|$(SECFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+FV = SECFV
+
+#####################################################################################################
+[FV.SECFV]
+FvNameGuid = 587d4265-5e71-41da-9c35-4258551f1e22
+BlockSize = $(BLOCK_SIZE)
+FvAlignment = 16
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+INF Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
+
+#####################################################################################################
+[Rule.Common.SEC]
+ FILE SEC = $(NAMED_GUID) {
+ TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
new file mode 100644
index 0000000000..a1a2d537e3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
@@ -0,0 +1,21 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+DEFINE BLOCK_SIZE = 0x1000
+
+############################################################################
+# fd total
+DEFINE FD_BASE_ADDRESS = 0x1c000000
+DEFINE FD_BLOCKS = 0x400
+DEFINE FD_SIZE = 0x400000
+
+############################################################################
+#flash code layout
+#Set Sec base address and size in flash
+DEFINE SECFV_OFFSET = 0x00000000
+DEFINE SECFV_SIZE = 0x00010000
diff --git a/Platform/Loongson/LoongArchQemuPkg/Readme.md b/Platform/Loongson/LoongArchQemuPkg/Readme.md
new file mode 100644
index 0000000000..809a199789
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Readme.md
@@ -0,0 +1,53 @@
+# Introduction
+
+ This document provides the guideline to build UEFI firmware for Qemu of LoongArch.
+
+ LoongArch is the general processor architecture of Loongson.
+
+ We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/.
+
+# How to build (X86 Linux Environment)
+
+ 1. Install LoongArch cross-tools on X86 machines.
+ Download cross-tools from https://github.com/loongson/ ,Then config cross-tools env.
+ For Example:
+
+ $ wget https://github.com/loongson/build-tools/releases/latest/download/loongarch64-clfs-20211202-cross-tools.tar.xz
+ $ tar -vxf loongarch64-clfs-20211202-cross-tools.tar.xz -C /opt
+ $ export PATH=/opt/cross-tools/bin:$PATH
+
+
+ 2. Follow edk2-platforms/Readme.md to obtaining source code,And config build env.
+ For Example:
+
+ $ export WORKSPACE=/work/git/tianocore
+ $ mkdir -p $WORKSPACE
+ $ cd $WORKSPACE
+ $ git clone https://github.com/tianocore/edk2.git
+ $ git submodule update --init
+ $ git clone https://github.com/tianocore/edk2-platforms.git
+ $ git submodule update --init
+ $ git clone https://github.com/tianocore/edk2-non-osi.git
+ $ export PACKAGES_PATH=$PWD/edk2:$PWD/edk2-platforms:$PWD/edk2-non-osi
+
+
+ 3. Config cross compiler prefix.
+ For Example:
+
+ $ export GCC5_LOONGARCH64_PREFIX=loongarch64-unknown-linux-gnu-
+
+
+ 4.Set up the build environment And build BaseTool.
+ For Example:
+
+ $. edk2/edksetup.sh
+ $make -C edk2/BaseTools
+
+
+ 5.Build platform.
+ For Exmaple:
+
+ $build --buildtarget=DEBUG --tagname=GCC5 --arch=LOONGARCH64 --platform=Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+
+
+ After a successful build, the resulting images can be found in `Build/{Platform Name}/{TARGET}_{TOOL_CHAIN_TAG}/FV`.
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S b/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
new file mode 100644
index 0000000000..48c044fe28
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/LoongArch64/Start.S
@@ -0,0 +1,76 @@
+#------------------------------------------------------------------------------
+#
+# Start for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Glossary:
+# - CSR - CPU Status Register
+# - EBASE - Exception Base Address
+#------------------------------------------------------------------------------
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include <Library/Cpu.h>
+#include "LoongArchAsmMacro.h"
+
+ .text
+ .globl _ModuleEntryPoint
+_ModuleEntryPoint:
+
+ /* configure reset ebase */
+ li.d T0, 0x1c000000
+ csrwr T0, LOONGARCH_CSR_EBASE
+
+ /*disable interrupt*/
+ li.d T0, (1 << 2)
+ csrxchg ZERO, T0, LOONGARCH_CSR_CRMD
+
+ /* read physical cpu number id */
+ csrrd T0, LOONGARCH_CSR_CPUNUM
+ andi T0, T0, 0x3ff
+ li.d A0, BOOTCORE_ID //0
+ bne T0, A0, slave_main
+
+call_centry:
+ /*call C function make sure parameter true*/
+ li.d A1, FixedPcdGet64(PcdSecPeiTempRamBase) + FixedPcdGet32(PcdSecPeiTempRamSize) # stack base
+ li.d A0, FixedPcdGet64(PcdFlashPeiFvBase) # PEI Fv base
+ move SP, A1
+ addi.d SP, SP, -0x8
+ bl SecCoreStartupWithStack
+
+slave_main:
+ # clear mailbox
+ li.d T1, LOONGSON_CSR_MAIL_BUF0
+ iocsrwr.d ZERO, T1
+
+ # enable IPI interrupt
+ li.d T0, (1 << 12)
+ csrxchg T0, T0, LOONGARCH_CSR_ECFG
+
+1:
+ # wait for wakeup
+ idle 0
+ nop
+ iocsrrd.w T0, T1
+ beqz T0, 1b
+
+ # read and clear ipi interrupt
+ li.d T1, LOONGSON_IOCSR_IPI_STATUS
+ iocsrrd.w T0, T1
+ li.d T1, LOONGSON_IOCSR_IPI_CLEAR
+ iocsrwr.w T0, T1
+
+ # disable IPI interrupt
+ li.d T0, (1 << 12)
+ csrxchg ZERO, T0, LOONGARCH_CSR_ECFG
+
+ # read mail buf and jump to specified entry
+ li.d T1, LOONGSON_CSR_MAIL_BUF0
+ iocsrrd.d T0, T1
+ or RA, T0, ZERO
+ jirl ZERO, RA, 0x0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
new file mode 100644
index 0000000000..73d3a2c1a3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.c
@@ -0,0 +1,510 @@
+/** @file
+ Main SEC phase code. Transitions to PEI.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/IoLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/PeCoffExtraActionLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+
+#include <Ppi/TemporaryRamSupport.h>
+
+/**
+ temporary memory to permanent memory and do stack switching.
+
+ @param[in] PeiServices Pointer to the PEI Services Table.
+ @param[in] TemporaryMemoryBase Temporary Memory Base address.
+ @param[in] PermanentMemoryBase Permanent Memory Base address.
+ @param[in] CopySize The size of memory that needs to be migrated.
+
+ @retval EFI_SUCCESS Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ );
+
+EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
+ TemporaryRamMigration
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiTemporaryRamSupportPpiGuid,
+ &mTemporaryRamSupportPpi
+ },
+};
+
+/**
+ Locates a section within a series of sections
+ with the specified section type.
+
+ The Instance parameter indicates which instance of the section
+ type to return. (0 is first instance, 1 is second...)
+
+ @param[in] Sections The sections to search
+ @param[in] SizeOfSections Total size of all sections
+ @param[in] SectionType The section type to locate
+ @param[in] Instance The section instance number
+ @param[out] FoundSection The FFS section if found
+
+ @retval EFI_SUCCESS The file and section was found
+ @retval EFI_NOT_FOUND The file and section was not found
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsSectionInstance (
+ IN VOID *Sections,
+ IN UINTN SizeOfSections,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN Instance,
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection
+ )
+{
+ EFI_PHYSICAL_ADDRESS CurrentAddress;
+ UINT32 Size;
+ EFI_PHYSICAL_ADDRESS EndOfSections;
+ EFI_COMMON_SECTION_HEADER *Section;
+ EFI_PHYSICAL_ADDRESS EndOfSection;
+
+ //
+ // Loop through the FFS file sections within the PEI Core FFS file
+ //
+ EndOfSection = (EFI_PHYSICAL_ADDRESS) (UINTN) Sections;
+ EndOfSections = EndOfSection + SizeOfSections;
+ for (;;) {
+ if (EndOfSection == EndOfSections) {
+ break;
+ }
+ CurrentAddress = (EndOfSection + 3) & ~(3ULL);
+ if (CurrentAddress >= EndOfSections) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ Section = (EFI_COMMON_SECTION_HEADER*) (UINTN) CurrentAddress;
+
+ Size = SECTION_SIZE (Section);
+ if (Size < sizeof (*Section)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ EndOfSection = CurrentAddress + Size;
+ if (EndOfSection > EndOfSections) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Look for the requested section type
+ //
+ if (Section->Type == SectionType) {
+ if (Instance == 0) {
+ *FoundSection = Section;
+ return EFI_SUCCESS;
+ } else {
+ Instance--;
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locates a section within a series of sections
+ with the specified section type.
+
+ @param[in] Sections The sections to search
+ @param[in] SizeOfSections Total size of all sections
+ @param[in] SectionType The section type to locate
+ @param[out] FoundSection The FFS section if found
+
+ @retval EFI_SUCCESS The file and section was found
+ @retval EFI_NOT_FOUND The file and section was not found
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsSectionInSections (
+ IN VOID *Sections,
+ IN UINTN SizeOfSections,
+ IN EFI_SECTION_TYPE SectionType,
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection
+ )
+{
+ return FindFfsSectionInstance (
+ Sections,
+ SizeOfSections,
+ SectionType,
+ 0,
+ FoundSection
+ );
+}
+
+/**
+ Locates a FFS file with the specified file type and a section
+ within that file with the specified section type.
+
+ @param[in] Fv The firmware volume to search
+ @param[in] FileType The file type to locate
+ @param[in] SectionType The section type to locate
+ @param[out] FoundSection The FFS section if found
+
+ @retval EFI_SUCCESS The file and section was found
+ @retval EFI_NOT_FOUND The file and section was not found
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindFfsFileAndSection (
+ IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_SECTION_TYPE SectionType,
+ OUT EFI_COMMON_SECTION_HEADER **FoundSection
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS CurrentAddress;
+ EFI_PHYSICAL_ADDRESS EndOfFirmwareVolume;
+ EFI_FFS_FILE_HEADER *File;
+ UINT32 Size;
+ EFI_PHYSICAL_ADDRESS EndOfFile;
+
+ if (Fv->Signature != EFI_FVH_SIGNATURE) {
+ DEBUG ((DEBUG_ERROR, "FV at %p does not have FV header signature\n", Fv));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ CurrentAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv;
+ EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
+
+ //
+ // Loop through the FFS files in the Boot Firmware Volume
+ //
+ for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
+
+ CurrentAddress = (EndOfFile + 7) & ~(7ULL);
+ if (CurrentAddress > EndOfFirmwareVolume) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ File = (EFI_FFS_FILE_HEADER*) (UINTN) CurrentAddress;
+ Size = *(UINT32*) File->Size & 0xffffff;
+ if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ EndOfFile = CurrentAddress + Size;
+ if (EndOfFile > EndOfFirmwareVolume) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ //
+ // Look for the request file type
+ //
+ if (File->Type != FileType) {
+ continue;
+ }
+
+ Status = FindFfsSectionInSections (
+ (VOID*) (File + 1),
+ (UINTN) EndOfFile - (UINTN) (File + 1),
+ SectionType,
+ FoundSection
+ );
+ if (!EFI_ERROR (Status)
+ || (Status == EFI_VOLUME_CORRUPTED))
+ {
+ return Status;
+ }
+ }
+}
+
+/**
+ Locates the PEI Core entry point address
+
+ @param[in] Fv The firmware volume to search
+ @param[out] PeiCoreEntryPoint The entry point of the PEI Core image
+
+ @retval EFI_SUCCESS The file and section was found
+ @retval EFI_NOT_FOUND The file and section was not found
+ @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
+
+**/
+EFI_STATUS
+FindPeiCoreImageBaseInFv (
+ IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
+ OUT EFI_PHYSICAL_ADDRESS *PeiCoreImageBase
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+ Status = FindFfsFileAndSection (
+ Fv,
+ EFI_FV_FILETYPE_PEI_CORE,
+ EFI_SECTION_PE32,
+ &Section
+ );
+ if (EFI_ERROR (Status)) {
+ Status = FindFfsFileAndSection (
+ Fv,
+ EFI_FV_FILETYPE_PEI_CORE,
+ EFI_SECTION_TE,
+ &Section
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Unable to find PEI Core image\n"));
+ return Status;
+ }
+ }
+
+ *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
+ return EFI_SUCCESS;
+}
+
+/**
+ Find and return Pei Core entry point.
+
+ It also find SEC and PEI Core file debug information. It will report them if
+ remote debug is enabled.
+
+**/
+VOID
+FindAndReportEntryPoints (
+ IN EFI_FIRMWARE_VOLUME_HEADER **BootFirmwareVolumePtr,
+ OUT EFI_PEI_CORE_ENTRY_POINT *PeiCoreEntryPoint
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PeiCoreImageBase = 0;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ Status = FindPeiCoreImageBaseInFv (*BootFirmwareVolumePtr, &PeiCoreImageBase);
+ ASSERT (Status == EFI_SUCCESS);
+
+ ZeroMem ((VOID *) &ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+
+ //
+ // Report PEI Core debug information when remote debug is enabled
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)PeiCoreImageBase;
+ ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*) (UINTN) ImageContext.ImageAddress);
+ PeCoffLoaderRelocateImageExtraAction (&ImageContext);
+
+ //
+ // Find PEI Core entry point
+ //
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
+ if (EFI_ERROR (Status)) {
+ *PeiCoreEntryPoint = 0;
+ }
+
+ return;
+}
+
+/**
+ Find the peicore entry point and jump to the entry point to execute.
+
+ @param[in] Context The first input parameter of InitializeDebugAgent().
+
+**/
+VOID
+EFIAPI
+SecStartupPhase2 (
+ IN VOID *Context
+ )
+{
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ EFI_FIRMWARE_VOLUME_HEADER *BootFv;
+ EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
+
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
+
+ //
+ // Find PEI Core entry point. It will report SEC and Pei Core debug information if remote debug
+ // is enabled.
+ //
+ BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
+ FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
+ SecCoreData->BootFirmwareVolumeBase = BootFv;
+ SecCoreData->BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
+
+ DEBUG ((DEBUG_INFO, "Find Pei EntryPoint=%p\n", PeiCoreEntryPoint));
+
+ //
+ // Transfer the control to the PEI core
+ //
+ DEBUG ((DEBUG_INFO, "SecStartupPhase2 %p\n", PeiCoreEntryPoint));
+
+ (*PeiCoreEntryPoint) (SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
+
+ //
+ // If we get here then the PEI Core returned, which is not recoverable.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
+/**
+ Entry point to the C language phase of SEC. initialize some temporary memory and set up the stack,
+ the control is transferred to this function.
+
+ @param[in] BootFv The pointer to the PEI FV in memory.
+ @param[in] TopOfCurrentStack Top of Current Stack.
+**/
+VOID
+EFIAPI
+SecCoreStartupWithStack (
+ IN EFI_FIRMWARE_VOLUME_HEADER *BootFv,
+ IN VOID *TopOfCurrentStack
+ )
+{
+ EFI_SEC_PEI_HAND_OFF SecCoreData;
+ EFI_FIRMWARE_VOLUME_HEADER *BootPeiFv = (EFI_FIRMWARE_VOLUME_HEADER*) BootFv;
+
+ DEBUG ((DEBUG_INFO, "Entering C environment\n"));
+
+ ProcessLibraryConstructorList (NULL, NULL);
+
+ DEBUG ((DEBUG_INFO,
+ "SecCoreStartupWithStack (0x%lx, 0x%lx)\n",
+ (UINTN)BootFv,
+ (UINTN)TopOfCurrentStack
+ ));
+ DEBUG ((DEBUG_INFO,
+ "(0x%lx, 0x%lx)\n",
+ (UINTN) (PcdGet64 (PcdSecPeiTempRamBase)),
+ (UINTN) (PcdGet32 (PcdSecPeiTempRamSize))
+ ));
+
+ // |-------------| <-- TopOfCurrentStack
+ // | Stack | 32k
+ // |-------------|
+ // | Heap | 32k
+ // |-------------| <-- SecCoreData.TemporaryRamBase
+ //
+
+ ASSERT ((UINTN) (PcdGet64 (PcdSecPeiTempRamBase) +
+ PcdGet32 (PcdSecPeiTempRamSize)) ==
+ (UINTN) TopOfCurrentStack);
+
+ //
+ // Initialize SEC hand-off state
+ //
+ SecCoreData.DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
+
+ SecCoreData.TemporaryRamSize = (UINTN) PcdGet32 (PcdSecPeiTempRamSize);
+ SecCoreData.TemporaryRamBase = (VOID *) PcdGet64 (PcdSecPeiTempRamBase);
+
+ SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
+ SecCoreData.PeiTemporaryRamSize = SecCoreData.TemporaryRamSize >> 1;
+
+ SecCoreData.StackBase = (UINT8 *)SecCoreData.TemporaryRamBase + SecCoreData.PeiTemporaryRamSize;
+ SecCoreData.StackSize = SecCoreData.TemporaryRamSize >> 1;
+
+ SecCoreData.BootFirmwareVolumeBase = BootPeiFv;
+ SecCoreData.BootFirmwareVolumeSize = (UINTN) BootPeiFv->FvLength;
+
+ DEBUG ((DEBUG_INFO,
+ "&SecCoreData.BootFirmwareVolumeBase=%lx SecCoreData.BootFirmwareVolumeBase=%lx\n",
+ (UINT64)&(SecCoreData.BootFirmwareVolumeBase),
+ (UINT64) (SecCoreData.BootFirmwareVolumeBase)));
+ DEBUG ((DEBUG_INFO,
+ "&SecCoreData.BootFirmwareVolumeSize=%lx SecCoreData.BootFirmwareVolumeSize=%lx\n",
+ (UINT64)&(SecCoreData.BootFirmwareVolumeSize),
+ (UINT64) (SecCoreData.BootFirmwareVolumeSize)));
+
+ //
+ // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, NULL, NULL);
+ SecStartupPhase2 (&SecCoreData);
+}
+
+/**
+ temporary memory to permanent memory and do stack switching.
+
+ @param[in] PeiServices Pointer to the PEI Services Table.
+ @param[in] TemporaryMemoryBase Temporary Memory Base address.
+ @param[in] PermanentMemoryBase Permanent Memory Base address.
+ @param[in] CopySize The size of memory that needs to be migrated.
+
+ @retval EFI_SUCCESS Migration successful.
+**/
+EFI_STATUS
+EFIAPI
+TemporaryRamMigration (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ )
+{
+ VOID *OldHeap;
+ VOID *NewHeap;
+ VOID *OldStack;
+ VOID *NewStack;
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+
+ DEBUG ((DEBUG_INFO,
+ "TemporaryRamMigration (0x%Lx, 0x%Lx, 0x%Lx)\n",
+ TemporaryMemoryBase,
+ PermanentMemoryBase,
+ (UINT64)CopySize
+ ));
+
+ OldHeap = (VOID*) (UINTN)TemporaryMemoryBase;
+ NewHeap = (VOID*) ((UINTN)PermanentMemoryBase + (CopySize >> 1));
+
+ OldStack = (VOID*) ((UINTN)TemporaryMemoryBase + (CopySize >> 1));
+ NewStack = (VOID*) (UINTN)PermanentMemoryBase;
+
+#if 0
+ DebugAgentContext.HeapMigrateOffset = (UINTN)NewHeap - (UINTN)OldHeap;
+ DebugAgentContext.StackMigrateOffset = (UINTN)NewStack - (UINTN)OldStack;
+
+ OldStatus = SaveAndSetDebugTimerInterrupt (FALSE);
+ InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, (VOID *) &DebugAgentContext, NULL);
+#endif
+
+ //
+ // 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);
+ }
+
+ //SaveAndSetDebugTimerInterrupt (OldStatus);
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
new file mode 100644
index 0000000000..03d4ea5b00
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
@@ -0,0 +1,49 @@
+## @file
+# SEC Driver
+#
+# Copyright (c) 2021 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
+
+[Sources.LOONGARCH64]
+ LoongArch64/Start.S
+ SecMain.c
+
+[Packages]
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ PcdLib
+ DebugAgentLib
+ IoLib
+ PeCoffLib
+ PeCoffGetEntryPointLib
+ PeCoffExtraActionLib
+
+[Ppis]
+ gEfiTemporaryRamSupportPpiGuid # PPI ALWAYS_PRODUCED
+
+[FixedPcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize
diff --git a/Readme.md b/Readme.md
index 62876b4b7d..825bd37edd 100644
--- a/Readme.md
+++ b/Readme.md
@@ -57,6 +57,7 @@ IA32 | i?86-linux-gnu-* _or_ x86_64-linux-gnu-
IPF | ia64-linux-gnu
X64 | x86_64-linux-gnu-
RISCV64 | riscv64-unknown-elf-
+LOONGARCH64 | loongarch64-linux-gnu-
\* i386, i486, i586 or i686
@@ -71,6 +72,11 @@ RISC-V open source community provides GCC toolchains for
[riscv64-unknown-elf](https://github.com/riscv/riscv-gnu-toolchain)
compiled to run on x86 Linux.
+### GCC for LoongArch
+Loonson open source community provides GCC toolchains for
+[loongarch64-unknown-elf](https://github.com/loongson/build-tools)
+compiled to run on x86 Linux
+
### clang
Clang does not require separate cross compilers, but it does need a
target-specific binutils. These are included with any prepackaged GCC toolchain
@@ -257,6 +263,9 @@ For more information, see the
##### Minnowboard Max/Turbot based on Intel Valleyview2 SoC
* [Minnowboard Max](Platform/Intel/Vlv2TbltDevicePkg)
+## Loongson
+* [LoongArchQemu](Platform/Loongson/LoongArchQemuPkg)
+
## Marvell
* [Armada 70x0](Platform/Marvell/Armada70x0Db)
* [Armada 80x0](Platform/Marvell/Armada80x0Db)
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 01/15] Platform/Loongson: Add Serial Port library xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 02/15] Platform/Loongson: Support SEC And Add Readme.md xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Use a register to save PeiServicesTable pointer,
This lib Provides PeiServicesTable pointer saving
and retrieval services.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../PeiServicesTablePointer.c | 78 +++++++++++++++++++
.../PeiServicesTablePointerLib.inf | 32 ++++++++
2 files changed, 110 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
new file mode 100644
index 0000000000..068960d4ce
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointer.c
@@ -0,0 +1,78 @@
+/** @file
+ PEI Services Table Pointer Library.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+
+/**
+ 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
+ )
+{
+ LOONGARCH_CSR_WRITEQ ((UINTN)PeiServicesTablePointer, LOONGARCH_CSR_KS0);
+}
+
+/**
+ Retrieves the cached value of the PEI Services Table pointer.
+
+ Returns the cached value of the PEI Services Table pointer in a CPU specific manner
+ as specified in the CPU binding section of the Platform Initialization Pre-EFI
+ Initialization Core Interface Specification.
+
+ If the cached PEI Services Table pointer is NULL, then ASSERT ().
+
+ @return The pointer to PeiServices.
+**/
+CONST EFI_PEI_SERVICES **
+EFIAPI
+GetPeiServicesTablePointer (
+ VOID
+ )
+{
+ UINTN val;
+
+ LOONGARCH_CSR_READQ (val, LOONGARCH_CSR_KS0);
+ return (CONST EFI_PEI_SERVICES **)val;
+}
+
+/**
+Perform CPU specific actions required to migrate the PEI Services Table
+pointer from temporary RAM to permanent RAM.
+
+For IA32 CPUs, the PEI Services Table pointer is stored in the 4 bytes
+immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+For X64 CPUs, the PEI Services Table pointer is stored in the 8 bytes
+immediately preceding the Interrupt Descriptor Table (IDT) in memory.
+For Itanium and ARM CPUs, a the PEI Services Table Pointer is stored in
+a dedicated CPU register. This means that there is no memory storage
+associated with storing the PEI Services Table pointer, so no additional
+migration actions are required for Itanium or ARM CPUs.
+
+**/
+VOID
+EFIAPI
+MigratePeiServicesTablePointer (
+VOID
+)
+{
+ return;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
new file mode 100644
index 0000000000..6fe76d1351
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
@@ -0,0 +1,32 @@
+## @file
+# PEI Services Table Pointer Library.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiServicesTablePointerLib
+ FILE_GUID = C3C9C4ED-EB8A-4548-BE1B-ABB0B6F35B1E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PeiServicesTablePointerLib|PEIM PEI_CORE SEC
+
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ PeiServicesTablePointer.c
+
+[Packages]
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+
+[Pcd]
+
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (2 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib xianglai
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
QemuFwCfgLib for PEI phase.
This library obtains the QemuFWCfg base address by
directly parsing the fdt, and reads and writes the data
in the QemuFWCfg by operating on the QemuFWCfg base address.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Include/IndustryStandard/QemuFwCfg.h | 95 ++++
.../Include/Library/QemuFwCfgLib.h | 179 +++++++
.../Library/QemuFwCfgLib/QemuFwCfg.c | 119 +++++
.../Library/QemuFwCfgLib/QemuFwCfgLib.c | 477 ++++++++++++++++++
.../Library/QemuFwCfgLib/QemuFwCfgLib.inf | 44 ++
.../QemuFwCfgLib/QemuFwCfgLibInternal.h | 64 +++
6 files changed, 978 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/IndustryStandard/QemuFwCfg.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfg.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/IndustryStandard/QemuFwCfg.h b/Platform/Loongson/LoongArchQemuPkg/Include/IndustryStandard/QemuFwCfg.h
new file mode 100644
index 0000000000..175da61816
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/IndustryStandard/QemuFwCfg.h
@@ -0,0 +1,95 @@
+/** @file
+ Macro and type definitions corresponding to the QEMU fw_cfg interface.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FW - FireWare
+ - CFG - Configure
+ - FNAME - File Name
+ - CTL - Contorl
+**/
+
+#ifndef QEMU_FW_CFG_H_
+#define QEMU_FW_CFG_H_
+
+#include <Base.h>
+
+//
+// The size, in bytes, of names of firmware configuration files, including at
+// least one terminating NUL byte.
+//
+#define QEMU_FW_CFG_FNAME_SIZE 56
+
+//
+// If the following bit is set in the UINT32 fw_cfg revision / feature bitmap
+// -- read from key 0x0001 with the basic IO Port or MMIO method --, then the
+// DMA interface is available.
+//
+#define FW_CFG_F_DMA BIT1
+
+//
+// Macros for the FW_CFG_DMA_ACCESS.Control bitmap (in native encoding).
+//
+#define FW_CFG_DMA_CTL_ERROR BIT0
+#define FW_CFG_DMA_CTL_READ BIT1
+#define FW_CFG_DMA_CTL_SKIP BIT2
+#define FW_CFG_DMA_CTL_SELECT BIT3
+#define FW_CFG_DMA_CTL_WRITE BIT4
+
+//
+// The fw_cfg registers can be found at these IO Ports, on the IO-mapped
+// platforms (Ia32 and X64).
+//
+#define FW_CFG_IO_SELECTOR 0x510
+#define FW_CFG_IO_DATA 0x511
+#define FW_CFG_IO_DMA_ADDRESS 0x514
+
+//
+// Numerically defined keys.
+//
+typedef enum {
+ QemuFwCfgItemSignature = 0x0000,
+ QemuFwCfgItemInterfaceVersion = 0x0001,
+ QemuFwCfgItemSystemUuid = 0x0002,
+ QemuFwCfgItemRamSize = 0x0003,
+ QemuFwCfgItemGraphicsEnabled = 0x0004,
+ QemuFwCfgItemSmpCpuCount = 0x0005,
+ QemuFwCfgItemMachineId = 0x0006,
+ QemuFwCfgItemKernelAddress = 0x0007,
+ QemuFwCfgItemKernelSize = 0x0008,
+ QemuFwCfgItemKernelCommandLine = 0x0009,
+ QemuFwCfgItemInitrdAddress = 0x000a,
+ QemuFwCfgItemInitrdSize = 0x000b,
+ QemuFwCfgItemBootDevice = 0x000c,
+ QemuFwCfgItemNumaData = 0x000d,
+ QemuFwCfgItemBootMenu = 0x000e,
+ QemuFwCfgItemMaximumCpuCount = 0x000f,
+ QemuFwCfgItemKernelEntry = 0x0010,
+ QemuFwCfgItemKernelData = 0x0011,
+ QemuFwCfgItemInitrdData = 0x0012,
+ QemuFwCfgItemCommandLineAddress = 0x0013,
+ QemuFwCfgItemCommandLineSize = 0x0014,
+ QemuFwCfgItemCommandLineData = 0x0015,
+ QemuFwCfgItemKernelSetupAddress = 0x0016,
+ QemuFwCfgItemKernelSetupSize = 0x0017,
+ QemuFwCfgItemKernelSetupData = 0x0018,
+ QemuFwCfgItemFileDir = 0x0019,
+
+} FIRMWARE_CONFIG_ITEM;
+
+//
+// Communication structure for the DMA access method. All fields are encoded in
+// big endian.
+//
+#pragma pack (1)
+typedef struct {
+ UINT32 Control;
+ UINT32 Length;
+ UINT64 Address;
+} FW_CFG_DMA_ACCESS;
+#pragma pack ()
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
new file mode 100644
index 0000000000..f3c73adfe7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/QemuFwCfgLib.h
@@ -0,0 +1,179 @@
+/** @file
+ QEMU/KVM Firmware Configuration access
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FW or Fw - Firmware
+ - Cfg - Configure
+**/
+
+#ifndef QEMU_FW_CFG_LIB_
+#define QEMU_FW_CFG_LIB_
+
+#include <IndustryStandard/QemuFwCfg.h>
+
+/**
+ Returns a boolean indicating if the firmware configuration interface
+ is available or not.
+
+ This function may change fw_cfg state.
+
+ @retval TRUE The interface is available
+ @retval FALSE The interface is not available
+
+**/
+BOOLEAN
+EFIAPI
+QemuFwCfgIsAvailable (
+ VOID
+ );
+
+
+/**
+ Selects a firmware configuration item for reading.
+
+ Following this call, any data read from this item will start from
+ the beginning of the configuration item's data.
+
+ @param[in] QemuFwCfgItem - Firmware Configuration item to read
+
+**/
+VOID
+EFIAPI
+QemuFwCfgSelectItem (
+ IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
+ );
+
+
+/**
+ Reads firmware configuration bytes into a buffer
+
+ If called multiple times, then the data read will
+ continue at the offset of the firmware configuration
+ item where the previous read ended.
+
+ @param[in] Size - Size in bytes to read
+ @param[in] Buffer - Buffer to store data into
+
+**/
+VOID
+EFIAPI
+QemuFwCfgReadBytes (
+ IN UINTN Size,
+ IN VOID *Buffer OPTIONAL
+ );
+
+
+/**
+ Writes firmware configuration bytes from a buffer
+
+ If called multiple times, then the data written will
+ continue at the offset of the firmware configuration
+ item where the previous write ended.
+
+ @param[in] Size - Size in bytes to write
+ @param[in] Buffer - Buffer to read data from
+
+**/
+VOID
+EFIAPI
+QemuFwCfgWriteBytes (
+ IN UINTN Size,
+ IN VOID *Buffer
+ );
+
+
+/**
+ Skip bytes in the firmware configuration item.
+
+ Increase the offset of the firmware configuration item without transferring
+ bytes between the item and a caller-provided buffer. Subsequent read, write
+ or skip operations will commence at the increased offset.
+
+ @param[in] Size Number of bytes to skip.
+**/
+VOID
+EFIAPI
+QemuFwCfgSkipBytes (
+ IN UINTN Size
+ );
+
+
+/**
+ Reads a UINT8 firmware configuration value
+
+ @retval Value of Firmware Configuration item read
+
+**/
+UINT8
+EFIAPI
+QemuFwCfgRead8 (
+ VOID
+ );
+
+
+/**
+ Reads a UINT16 firmware configuration value
+
+ @retval Value of Firmware Configuration item read
+
+**/
+UINT16
+EFIAPI
+QemuFwCfgRead16 (
+ VOID
+ );
+
+
+/**
+ Reads a UINT32 firmware configuration value
+
+ @retval Value of Firmware Configuration item read
+
+**/
+UINT32
+EFIAPI
+QemuFwCfgRead32 (
+ VOID
+ );
+
+
+/**
+ Reads a UINT64 firmware configuration value
+
+ @retval Value of Firmware Configuration item read
+
+**/
+UINT64
+EFIAPI
+QemuFwCfgRead64 (
+ VOID
+ );
+
+
+/**
+ Find the configuration item corresponding to the firmware configuration file.
+
+ @param[in] Name - Name of file to look up.
+ @param[out] Item - Configuration item corresponding to the file, to be passed
+ to QemuFwCfgSelectItem ().
+ @param[out] Size - Number of bytes in the file.
+
+ @retval RETURN_SUCCESS If file is found.
+ RETURN_NOT_FOUND If file is not found.
+ RETURN_UNSUPPORTED If firmware configuration is unavailable.
+
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgFindFile (
+ IN CONST CHAR8 *Name,
+ OUT FIRMWARE_CONFIG_ITEM *Item,
+ OUT UINTN *Size
+ );
+
+#endif
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfg.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfg.c
new file mode 100644
index 0000000000..91995c90b5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfg.c
@@ -0,0 +1,119 @@
+/** @file
+ fw_cfg library implementation.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FwCfg - firmWare Configure
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/QemuFwCfgLib.h>
+
+#include "QemuFwCfgLibInternal.h"
+
+/**
+ Returns a boolean indicating if the firmware configuration interface
+ is available or not.
+
+ This function may change fw_cfg state.
+
+ @retval TRUE The interface is available
+ @retval FALSE The interface is not available
+
+**/
+BOOLEAN
+EFIAPI
+QemuFwCfgIsAvailable (
+ VOID
+ )
+{
+ UINT32 Signature;
+ UINT32 Revision;
+
+ QemuFwCfgSelectItem (QemuFwCfgItemSignature);
+ Signature = QemuFwCfgRead32 ();
+ DEBUG ((DEBUG_INFO, "FW CFG Signature: 0x%x\n", Signature));
+ QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion);
+ Revision = QemuFwCfgRead32 ();
+ DEBUG ((DEBUG_INFO, "FW CFG Revision: 0x%x\n", Revision));
+ if ((Signature != SIGNATURE_32 ('Q', 'E', 'M', 'U'))
+ || (Revision < 1))
+ {
+ DEBUG ((DEBUG_INFO, "QemuFwCfg interface not supported.\n"));
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, "QemuFwCfg interface is supported.\n"));
+ return TRUE;
+}
+
+
+/**
+ Returns a boolean indicating if the firmware configuration interface is
+ available for library-internal purposes.
+
+ This function never changes fw_cfg state.
+
+ @retval TRUE The interface is available internally.
+ @retval FALSE The interface is not available internally.
+**/
+BOOLEAN
+InternalQemuFwCfgIsAvailable (
+ VOID
+ )
+{
+ //
+ // We always return TRUE, because the consumer of this library ought to have
+ // called QemuFwCfgIsAvailable before making other calls which would hit this
+ // path.
+ //
+ return TRUE;
+}
+
+/**
+ Returns a boolean indicating whether QEMU provides the DMA-like access method
+ for fw_cfg.
+
+ @retval TRUE The DMA-like access method is available.
+ @retval FALSE The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+ VOID
+ )
+{
+ return FALSE;
+}
+
+/**
+ Transfer an array of bytes, or skip a number of bytes, using the DMA
+ interface.
+
+ @param[in] Size Size in bytes to transfer or skip.
+
+ @param[in, out] Buffer Buffer to read data into or write data from. Ignored,
+ and may be NULL, if Size is zero, or Control is
+ FW_CFG_DMA_CTL_SKIP.
+
+ @param[in] Control One of the following:
+ FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
+ FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
+ FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+ IN UINT32 Size,
+ IN OUT VOID *Buffer OPTIONAL,
+ IN UINT32 Control
+ )
+{
+ //
+ // We should never reach here
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
new file mode 100644
index 0000000000..23da05ee91
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
@@ -0,0 +1,477 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FwCfg - firmWare Configure
+ - CTL - Control
+**/
+
+#include "Uefi.h"
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <libfdt.h>
+#include "QemuFwCfgLibInternal.h"
+
+STATIC UINTN mFwCfgSelectorAddress;
+STATIC UINTN mFwCfgDataAddress;
+/**
+ To get firmware configure selector address.
+
+ @param VOID
+
+ @retval firmware configure selector address
+**/
+UINTN
+EFIAPI
+QemuGetFwCfgSelectorAddress (
+ VOID
+ )
+{
+ UINTN FwCfgSelectorAddress = mFwCfgSelectorAddress;
+ if (FwCfgSelectorAddress == 0) {
+ FwCfgSelectorAddress = (UINTN)PcdGet64 (PcdFwCfgSelectorAddress);
+ }
+ return FwCfgSelectorAddress;
+}
+/**
+ To get firmware configure Data address.
+
+ @param VOID
+
+ @retval firmware configure data address
+**/
+UINTN
+EFIAPI
+QemuGetFwCfgDataAddress (
+ VOID
+ )
+{
+ UINTN FwCfgDataAddress = mFwCfgDataAddress;
+ if (FwCfgDataAddress == 0) {
+ FwCfgDataAddress = (UINTN)PcdGet64 (PcdFwCfgDataAddress);
+ }
+ return FwCfgDataAddress;
+}
+/**
+ Selects a firmware configuration item for reading.
+
+ Following this call, any data read from this item will start from
+ the beginning of the configuration item's data.
+
+ @param[in] QemuFwCfgItem - Firmware Configuration item to read
+
+**/
+VOID
+EFIAPI
+QemuFwCfgSelectItem (
+ IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem
+ )
+{
+ UINTN FwCfgSelectorAddress;
+ FwCfgSelectorAddress = QemuGetFwCfgSelectorAddress ();
+ MmioWrite16 (FwCfgSelectorAddress, SwapBytes16((UINT16) (UINTN)QemuFwCfgItem));
+}
+
+/**
+ Slow READ_BYTES_FUNCTION.
+
+ @param[in] The size of the data to be read.
+ @param[in] Buffer The buffer that stores the readout data.
+**/
+VOID
+EFIAPI
+MmioReadBytes (
+ IN UINTN Size,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ UINTN Left;
+ UINT8 *Ptr;
+ UINT8 *End;
+ UINTN FwCfgDataAddress;
+ Left = Size & 7;
+
+ Size -= Left;
+ Ptr = Buffer;
+ End = Ptr + Size;
+ FwCfgDataAddress = QemuGetFwCfgDataAddress ();
+ while (Ptr < End) {
+ *(UINT64 *)Ptr = MmioRead64 (FwCfgDataAddress);
+ Ptr += 8;
+ }
+ if (Left & 4) {
+ *(UINT32 *)Ptr = MmioRead32 (FwCfgDataAddress);
+ Ptr += 4;
+ }
+ if (Left & 2) {
+ *(UINT16 *)Ptr = MmioRead16 (FwCfgDataAddress);
+ Ptr += 2;
+ }
+ if (Left & 1) {
+ *Ptr = MmioRead8 (FwCfgDataAddress);
+ }
+}
+
+/**
+ Slow WRITE_BYTES_FUNCTION.
+
+ @param[in] The size of the data to be write.
+ @param[in] Buffer The buffer that stores the writein data.
+**/
+VOID
+EFIAPI
+MmioWriteBytes (
+ IN UINTN Size,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ UINTN Idx;
+ UINTN FwCfgDataAddress;
+ FwCfgDataAddress = QemuGetFwCfgDataAddress ();
+ for (Idx = 0; Idx < Size; ++Idx) {
+ MmioWrite8 (FwCfgDataAddress, ((UINT8 *)Buffer)[Idx]);
+ }
+}
+
+/**
+ Reads firmware configuration bytes into a buffer
+
+ @param[in] Size - Size in bytes to read
+ @param[in] Buffer - Buffer to store data into (OPTIONAL if Size is 0)
+
+**/
+VOID
+EFIAPI
+InternalQemuFwCfgReadBytes (
+ IN UINTN Size,
+ IN VOID *Buffer OPTIONAL
+ )
+{
+ if ((InternalQemuFwCfgDmaIsAvailable ())
+ && (Size <= MAX_UINT32))
+ {
+ InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_READ);
+ return;
+ }
+ MmioReadBytes (Size, Buffer);
+}
+
+
+/**
+ Reads firmware configuration bytes into a buffer
+
+ If called multiple times, then the data read will
+ continue at the offset of the firmware configuration
+ item where the previous read ended.
+
+ @param[in] Size - Size in bytes to read
+ @param[in] Buffer - Buffer to store data into
+**/
+VOID
+EFIAPI
+QemuFwCfgReadBytes (
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ if (InternalQemuFwCfgIsAvailable ()) {
+ InternalQemuFwCfgReadBytes (Size, Buffer);
+ } else {
+ ZeroMem (Buffer, Size);
+ }
+}
+
+/**
+ Write firmware configuration bytes from a buffer
+
+ If called multiple times, then the data written will
+ continue at the offset of the firmware configuration
+ item where the previous write ended.
+
+ @param[in] Size - Size in bytes to write
+ @param[in] Buffer - Buffer to read data from
+**/
+VOID
+EFIAPI
+QemuFwCfgWriteBytes (
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ if (InternalQemuFwCfgIsAvailable ()) {
+ if ((InternalQemuFwCfgDmaIsAvailable ())
+ && (Size <= MAX_UINT32))
+ {
+ InternalQemuFwCfgDmaBytes ((UINT32)Size, Buffer, FW_CFG_DMA_CTL_WRITE);
+ return;
+ }
+ MmioWriteBytes (Size, Buffer);
+ }
+}
+
+
+/**
+ Skip bytes in the firmware configuration item.
+
+ Increase the offset of the firmware configuration item without transferring
+ bytes between the item and a caller-provided buffer. Subsequent read, write
+ or skip operations will commence at the increased offset.
+
+ @param[in] Size Number of bytes to skip.
+**/
+VOID
+EFIAPI
+QemuFwCfgSkipBytes (
+ IN UINTN Size
+ )
+{
+ UINTN ChunkSize;
+ UINT8 SkipBuffer[256];
+
+ if (!InternalQemuFwCfgIsAvailable ()) {
+ return;
+ }
+
+ if ((InternalQemuFwCfgDmaIsAvailable ())
+ && (Size <= MAX_UINT32))
+ {
+ InternalQemuFwCfgDmaBytes ((UINT32)Size, NULL, FW_CFG_DMA_CTL_SKIP);
+ return;
+ }
+
+ //
+ // Emulate the skip by reading data in chunks, and throwing it away. The
+ // implementation below is suitable even for phases where RAM or dynamic
+ // allocation is not available or appropriate. It also doesn't affect the
+ // static data footprint for client modules. Large skips are not expected,
+ // therefore this fallback is not performance critical. The size of
+ // SkipBuffer is thought not to exert a large pressure on the stack in any
+ // phase.
+ //
+ while (Size > 0) {
+ ChunkSize = MIN (Size, sizeof SkipBuffer);
+ MmioReadBytes (ChunkSize, SkipBuffer);
+ Size -= ChunkSize;
+ }
+}
+
+
+/**
+ Reads a UINT8 firmware configuration value
+
+ @return Value of Firmware Configuration item read
+
+**/
+UINT8
+EFIAPI
+QemuFwCfgRead8 (
+ VOID
+ )
+{
+ UINT8 Result;
+
+ QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+ return Result;
+}
+
+
+/**
+ Reads a UINT16 firmware configuration value
+
+ @return Value of Firmware Configuration item read
+
+**/
+UINT16
+EFIAPI
+QemuFwCfgRead16 (
+ VOID
+ )
+{
+ UINT16 Result;
+
+ QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+ return Result;
+}
+
+
+/**
+ Reads a UINT32 firmware configuration value
+
+ @return Value of Firmware Configuration item read
+
+**/
+UINT32
+EFIAPI
+QemuFwCfgRead32 (
+ VOID
+ )
+{
+ UINT32 Result;
+
+ QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+ return Result;
+}
+
+
+/**
+ Reads a UINT64 firmware configuration value
+
+ @return Value of Firmware Configuration item read
+
+**/
+UINT64
+EFIAPI
+QemuFwCfgRead64 (
+ VOID
+ )
+{
+ UINT64 Result;
+
+ QemuFwCfgReadBytes (sizeof (Result), &Result);
+
+ return Result;
+}
+
+
+/**
+ Find the configuration item corresponding to the firmware configuration file.
+
+ @param[in] Name - Name of file to look up.
+ @param[out] Item - Configuration item corresponding to the file, to be passed
+ to QemuFwCfgSelectItem ().
+ @param[out] Size - Number of bytes in the file.
+
+ @return RETURN_SUCCESS If file is found.
+ RETURN_NOT_FOUND If file is not found.
+ RETURN_UNSUPPORTED If firmware configuration is unavailable.
+
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgFindFile (
+ IN CONST CHAR8 *Name,
+ OUT FIRMWARE_CONFIG_ITEM *Item,
+ OUT UINTN *Size
+ )
+{
+ UINT32 Count;
+ UINT32 Idx;
+
+ if (!InternalQemuFwCfgIsAvailable ()) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ QemuFwCfgSelectItem (QemuFwCfgItemFileDir);
+ Count = SwapBytes32 (QemuFwCfgRead32 ());
+
+ for (Idx = 0; Idx < Count; ++Idx) {
+ UINT32 FileSize;
+ UINT16 FileSelect;
+ CHAR8 FileName[QEMU_FW_CFG_FNAME_SIZE];
+
+ FileSize = QemuFwCfgRead32 ();
+ FileSelect = QemuFwCfgRead16 ();
+ QemuFwCfgRead16 (); // skip the field called "reserved"
+ InternalQemuFwCfgReadBytes (sizeof (FileName), FileName);
+
+ if (AsciiStrCmp (Name, FileName) == 0) {
+ *Item = SwapBytes16 (FileSelect);
+ *Size = SwapBytes32 (FileSize);
+ return RETURN_SUCCESS;
+ }
+ }
+
+ return RETURN_NOT_FOUND;
+}
+
+/**
+ firmware config initialize.
+
+ @param VOID
+
+ @return RETURN_SUCCESS Initialization succeeded.
+**/
+RETURN_STATUS
+EFIAPI
+QemuFwCfgInitialize (
+ VOID
+ )
+{
+ VOID *DeviceTreeBase;
+ INT32 Node;
+ INT32 Prev;
+ CONST CHAR8 *Type;
+ INT32 Len;
+ CONST UINT64 *RegProp;
+ UINT64 FwCfgSelectorAddress;
+ UINT64 FwCfgDataAddress;
+ UINT64 FwCfgDataSize;
+ RETURN_STATUS PcdStatus;
+
+ DeviceTreeBase = (VOID *) (UINTN)PcdGet64 (PcdDeviceTreeBase);
+ ASSERT (DeviceTreeBase != NULL);
+ //
+ // Make sure we have a valid device tree blob
+ //
+ ASSERT (fdt_check_header (DeviceTreeBase) == 0);
+
+ for (Prev = 0;; Prev = Node) {
+ Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
+ if (Node < 0) {
+ break;
+ }
+
+ //
+ // Check for memory node
+ //
+ Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
+ if ((Type)
+ && (AsciiStrnCmp (Type, "qemu,fw-cfg-mmio", Len) == 0))
+ {
+ //
+ // Get the 'reg' property of this node. For now, we will assume
+ // two 8 byte quantities for base and size, respectively.
+ //
+ RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
+ if ((RegProp != 0)
+ && (Len == (2 * sizeof (UINT64))))
+ {
+ FwCfgDataAddress = SwapBytes64 (RegProp[0]);
+ FwCfgDataSize = SwapBytes64 (RegProp[1]);
+ FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
+
+ mFwCfgSelectorAddress = FwCfgSelectorAddress;
+ mFwCfgDataAddress = FwCfgDataAddress;
+
+ PcdStatus = PcdSet64S (
+ PcdFwCfgSelectorAddress,
+ FwCfgSelectorAddress
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+ PcdStatus = PcdSet64S (
+ PcdFwCfgDataAddress,
+ FwCfgDataAddress
+ );
+ ASSERT_RETURN_ERROR (PcdStatus);
+ break;
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to parse FDT QemuCfg node\n",
+ __FUNCTION__));
+ break;
+ }
+ }
+ }
+ return RETURN_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
new file mode 100644
index 0000000000..9fcde1a4d5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
@@ -0,0 +1,44 @@
+## @file
+# initialized fw_cfg library.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = QemuFwCfgSecLib
+ FILE_GUID = cdf9a9d5-7422-4dcb-b41d-607151ad320b
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = QemuFwCfgLib
+
+ CONSTRUCTOR = QemuFwCfgInitialize
+
+
+[Sources]
+ QemuFwCfgLibInternal.h
+ QemuFwCfgLib.c
+ QemuFwCfg.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ MemoryAllocationLib
+ FdtLib
+ PcdLib
+
+[Pcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgSelectorAddress
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgDataAddress
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
new file mode 100644
index 0000000000..33eeb927dd
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
@@ -0,0 +1,64 @@
+/** @file
+ fw_cfg library implementation.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FwCfg - firmWare Configure
+**/
+
+#ifndef QEMU_FW_CFG_LIB_INTERNAL_H_
+#define QEMU_FW_CFG_LIB_INTERNAL_H_
+
+/**
+ Returns a boolean indicating if the firmware configuration interface is
+ available for library-internal purposes.
+
+ This function never changes fw_cfg state.
+
+ @retval TRUE The interface is available internally.
+ @retval FALSE The interface is not available internally.
+**/
+BOOLEAN
+InternalQemuFwCfgIsAvailable (
+ VOID
+ );
+
+
+/**
+ Returns a boolean indicating whether QEMU provides the DMA-like access method
+ for fw_cfg.
+
+ @retval TRUE The DMA-like access method is available.
+ @retval FALSE The DMA-like access method is unavailable.
+**/
+BOOLEAN
+InternalQemuFwCfgDmaIsAvailable (
+ VOID
+ );
+
+/**
+ Transfer an array of bytes, or skip a number of bytes, using the DMA
+ interface.
+
+ @param[in] Size Size in bytes to transfer or skip.
+
+ @param[in,out] Buffer Buffer to read data into or write data from. Ignored,
+ and may be NULL, if Size is zero, or Control is
+ FW_CFG_DMA_CTL_SKIP.
+
+ @param[in] Control One of the following:
+ FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.
+ FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer.
+ FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg.
+**/
+VOID
+InternalQemuFwCfgDmaBytes (
+ IN UINT32 Size,
+ IN OUT VOID *Buffer OPTIONAL,
+ IN UINT32 Control
+ );
+
+#endif
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (3 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib xianglai
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
This library provides interfaces for creating kernel boot parameters.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LoongArchQemuPkg/Include/Library/Bpi.h | 77 +++
.../LoongArchQemuPkg/Library/BpiLib/Bpi.c | 492 ++++++++++++++++++
.../Library/BpiLib/BpiLib.inf | 38 ++
3 files changed, 607 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/Bpi.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/Bpi.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/Bpi.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Bpi.h
new file mode 100644
index 0000000000..cb2585ccb7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/Bpi.h
@@ -0,0 +1,77 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - BPI or Bpi - Boot Parameter Interface
+ - MEM or Mem - Memory
+ - info or INFO - Information
+ - SINFO - Screen information
+**/
+#ifndef BPI_H_
+#define BPI_H_
+
+#include <IndustryStandard/LinuxBzimage.h>
+#define SYSTEM_RAM 1
+#define SYSTEM_RAM_RESERVED 2
+#define ACPI_TABLE 3
+#define ACPI_NVS 4
+#define SYSTEM_PMEM 5
+
+#define MAX_MEM_MAP 128
+
+#define DEBUG_BPI
+
+#define MAP_ENTRY(Entry, Type, Start, Size) \
+ MemMap->Map[(Entry)].MemType = (Type), \
+ MemMap->Map[(Entry)].MemStart = (Start), \
+ MemMap->Map[(Entry)].MemSize = (Size), \
+ Entry++
+
+#pragma pack(1)
+typedef struct _extension_list_hdr{
+ UINT64 Signature;
+ UINT32 Length;
+ UINT8 Revision;
+ UINT8 CheckSum;
+ struct _extension_list_hdr *next;
+}EXT_LIST;
+
+typedef struct _BootParams_Interface {
+ UINT64 Signature; //{'B', 'P', 'I', '0', '1', '0', '0', '1'}
+ EFI_SYSTEM_TABLE *SystemTable;
+ EXT_LIST *ExtList;
+}BootParamsInterface;
+
+typedef struct _MEMMAP_ {
+ UINT32 MemType;
+ UINT64 MemStart;
+ UINT64 MemSize;
+}MEMMAP;
+
+typedef struct _MEM_MAP_ {
+ EXT_LIST Header; // {'M', 'E', 'M'}
+ UINT8 MapCount;
+ MEMMAP Map[MAX_MEM_MAP];
+} MEM_MAP;
+
+typedef struct {
+ EXT_LIST Header; // {SI}
+ struct screen_info si;
+}SINFO;
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT64 Length;
+ UINT32 Type;
+ UINT32 Reserved;
+} LOONGARCH_MEMMAP_ENTRY;
+
+#pragma pack()
+
+typedef struct screen_info SCREEN_INFO;
+
+#endif
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/Bpi.c b/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/Bpi.c
new file mode 100644
index 0000000000..c36ade6be9
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/Bpi.c
@@ -0,0 +1,492 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Bpi - Boot Parameter Interface
+ - Calc - Calculation
+ - Mem - memory
+ - Ext - Exist
+ - FwCfg - firmWare Configure
+ - si - Screen Information
+ - pos - Position
+**/
+#include "Uefi.h"
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/Bpi.h>
+
+/*
+ Calculates the checksum and saves the result at the end of the data.
+
+ @param Buffer A pointer to the data to calculate the checksum.
+ @param Size The number of data involved in calculating the checksum.
+
+ @retval VOID
+ */
+VOID
+BpiChecksum (
+ IN UINT8 *Buffer,
+ IN UINTN Size
+ )
+{
+ UINTN ChecksumOffset;
+
+ //
+ // CheckSum's offset in EXT_LIST is the same as in EXT_LIST's container (Buffer).
+ //
+ ChecksumOffset = OFFSET_OF (EXT_LIST, CheckSum);
+
+ //
+ // set checksum to 0 first
+ //
+ Buffer[ChecksumOffset] = 0;
+
+ //
+ // Update checksum value
+ //
+ Buffer[ChecksumOffset] = CalculateCheckSum8 (Buffer, Size);
+}
+
+/*
+ Add a linked list node to the linked list.
+
+ @param Bpi A pointer to the structure that holds the header of the linked list.
+ @param Header The address of the node to join the linked list.
+
+ @retval VOID
+ */
+VOID
+EFIAPI
+AddToList (
+ IN BootParamsInterface *Bpi,
+ OUT EXT_LIST *Header
+ )
+{
+ EXT_LIST *LastHeader;
+
+ if (Bpi->ExtList == NULL) {
+ Bpi->ExtList = Header;
+ } else {
+ for (LastHeader = Bpi->ExtList; LastHeader->next; LastHeader = LastHeader->next) {
+ }
+ LastHeader->next = Header;
+ BpiChecksum ((UINT8 *)LastHeader, LastHeader->Length);
+ }
+ Header->next = NULL;
+ BpiChecksum ((UINT8 *)Header, Header->Length);
+}
+
+#ifdef DEBUG_BPI
+/*
+ Iterates through the linked list and prints the data in all linked list nodes.
+
+ @param Bpi A pointer to the structure that holds the header of the linked list.
+
+ @retval VOID
+ */
+VOID
+EFIAPI
+ShowList (
+ IN BootParamsInterface *Bpi
+ )
+{
+ EXT_LIST *LastHeader;
+
+ if (Bpi->ExtList == NULL) {
+ DEBUG ((DEBUG_INFO, "List is null\n"));
+ } else {
+ for (LastHeader = Bpi->ExtList; LastHeader; LastHeader = LastHeader->next) {
+ DEBUG ((DEBUG_INFO, "Header: 0x%llx, Legth: 0x%x, CheckSum: 0x%x\n", LastHeader, LastHeader->Length,
+ LastHeader->CheckSum));
+ }
+ }
+}
+#endif
+/*
+ Read fwCfg to get the memory-mapped information and add it to the linked list.
+
+ @param Bpi A pointer to the structure that holds the header of the linked list.
+ @param MemMap A pointer to a memory-mapped struct.
+
+ @retval VOID
+ */
+VOID
+EFIAPI
+InitMemMap (
+ IN OUT BootParamsInterface *Bpi,
+ OUT MEM_MAP *MemMap
+ )
+{
+ UINT64 RamSize;
+ UINT8 Data[8] = {'M', 'E', 'M'};
+ INTN i = 0;
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ LOONGARCH_MEMMAP_ENTRY MemMapEntry;
+ LOONGARCH_MEMMAP_ENTRY *StartEntry;
+ LOONGARCH_MEMMAP_ENTRY *pEntry;
+ UINTN Processed;
+
+ SetMem (&MemMap->Header, sizeof (EXT_LIST), 0);
+
+ CopyMem (&MemMap->Header.Signature, Data, sizeof (EXT_LIST));
+ MemMap->Header.Revision = 0;
+ MemMap->Header.Length = sizeof (MEM_MAP);
+
+ RamSize = PcdGet64 (PcdRamSize); //in Byte
+
+ ASSERT (RamSize != 0);
+ DEBUG ((DEBUG_INFO, "RamSize %lld Byte\n", RamSize));
+
+ /*
+ * 1. The lowest 2M region cannot record in MemMap, cause Linux ram region should begin with usable ram.
+ * MAP_ENTRY (i, SYSTEM_RAM_RESERVED, 0x0, 0x200000); // 0x0-0x200000
+ */
+
+ /* 2. Available SYSTEM_RAM area. */
+ MAP_ENTRY (i, SYSTEM_RAM, 0x200000, 0xf000000 - 0x200000); // 0x200000~0xf000000
+
+ /* 3. Reserved low memory highest 16M. */
+ MAP_ENTRY (i, SYSTEM_RAM_RESERVED, 0xf000000, 0x1000000); // 0xf000000~0x10000000
+ /*
+ * 0x90000000 -- 0xC0000000 is used by uefi bios
+ */
+ //MAP_ENTRY (i, SYSTEM_RAM, 0x90000000, 0x30000000);
+
+
+ /* Read memmap from QEMU when RamSize is larger than 1G */
+ if (RamSize > SIZE_1GB) {
+ Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "fw read etc/la_memmap error Status %d \n", Status));
+ }
+ if (FwCfgSize % sizeof MemMapEntry != 0) {
+ DEBUG ((DEBUG_ERROR, "no MemMapEntry FwCfgSize:%d\n", FwCfgSize));
+ }
+
+ QemuFwCfgSelectItem (FwCfgItem);
+ StartEntry = AllocateZeroPool (FwCfgSize);
+ QemuFwCfgReadBytes (FwCfgSize, StartEntry);
+ for (Processed = 0; Processed < (FwCfgSize / sizeof MemMapEntry); Processed++) {
+ pEntry = StartEntry + Processed;
+ DEBUG ((
+ DEBUG_INFO,
+ "%a:%d Base=0x%Lx Length=0x%Lx Type=%u sizeof (MemMapEntry):%d, Processed:%d, FwCfgSize:%d\n",
+ __FUNCTION__,
+ __LINE__,
+ pEntry->BaseAddr,
+ pEntry->Length,
+ pEntry->Type,
+ sizeof MemMapEntry,
+ Processed,
+ FwCfgSize
+ ));
+ MAP_ENTRY (i, pEntry->Type, pEntry->BaseAddr, pEntry->Length);
+ }
+ }
+
+ MemMap->MapCount = i;
+ AddToList (Bpi, &MemMap->Header);
+#ifdef DEBUG_BPI
+ INTN j;
+ for (j = 0; j < i; j++) {
+ DEBUG ((DEBUG_INFO, "%d: type: 0x%x, start: 0x%llx, size: 0x%llx\n", j, MemMap->Map[j].MemType,
+ MemMap->Map[j].MemStart, MemMap->Map[j].MemSize));
+ }
+#endif
+}
+/*
+ Find the first bit field with 1 and get its starting position and length.
+
+ @param Mask To find data for the bit field.
+ @param Pos Find the starting location of the bit domain.
+ @param Size The length of the bit domain found.
+
+ @retval VOID
+ */
+VOID
+FindBits (
+ IN UINT64 Mask,
+ OUT UINT8 *Pos,
+ OUT UINT8 *Size
+ )
+{
+ UINT8 First;
+ UINT8 Len;
+
+ First = 0;
+ Len = 0;
+
+ if (Mask) {
+ while (!(Mask & 0x1)) {
+ Mask = Mask >> 1;
+ First++;
+ }
+
+ while (Mask & 0x1) {
+ Mask = Mask >> 1;
+ Len++;
+ }
+ }
+ *Pos = First;
+ *Size = Len;
+}
+
+/*
+ Establish graph-related parameters by EFI_GRAPHICS_OUTPUT_PROTOCOL.
+
+ @param Si A pointer to the SCREEN_INFO struct.
+ @param Gop A pointer to the EFI_GRAPHICS_OUTPUT_PROTOCOL structure.
+
+ @retval VOID
+ */
+EFI_STATUS
+SetupGraphicsFromGop (
+ OUT SCREEN_INFO *Si,
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop
+ )
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Status = Gop->QueryMode (Gop, Gop->Mode->Mode, &Size, &Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ /* We found a GOP */
+
+ /* EFI framebuffer */
+ Si->orig_video_isVGA = 0x70;
+
+ Si->orig_x = 0;
+ Si->orig_y = 0;
+ Si->orig_video_page = 0;
+ Si->orig_video_mode = 0;
+ Si->orig_video_cols = 0;
+ Si->orig_video_lines = 0;
+ Si->orig_video_ega_bx = 0;
+ Si->orig_video_points = 0;
+
+ Si->lfb_base = (UINT32) Gop->Mode->FrameBufferBase;
+ Si->lfb_size = (UINT32) Gop->Mode->FrameBufferSize;
+ Si->lfb_width = (UINT16) Info->HorizontalResolution;
+ Si->lfb_height = (UINT16) Info->VerticalResolution;
+ Si->pages = 1;
+ Si->vesapm_seg = 0;
+ Si->vesapm_off = 0;
+
+ if (Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) {
+ Si->lfb_depth = 32;
+ Si->red_size = 8;
+ Si->red_pos = 0;
+ Si->green_size = 8;
+ Si->green_pos = 8;
+ Si->blue_size = 8;
+ Si->blue_pos = 16;
+ Si->rsvd_size = 8;
+ Si->rsvd_pos = 24;
+ Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+ } else if (Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) {
+ Si->lfb_depth = 32;
+ Si->red_size = 8;
+ Si->red_pos = 16;
+ Si->green_size = 8;
+ Si->green_pos = 8;
+ Si->blue_size = 8;
+ Si->blue_pos = 0;
+ Si->rsvd_size = 8;
+ Si->rsvd_pos = 24;
+ Si->lfb_linelength = (UINT16) (Info->PixelsPerScanLine * 4);
+ } else if (Info->PixelFormat == PixelBitMask) {
+ FindBits (Info->PixelInformation.RedMask,
+ &Si->red_pos, &Si->red_size);
+ FindBits (Info->PixelInformation.GreenMask,
+ &Si->green_pos, &Si->green_size);
+ FindBits (Info->PixelInformation.BlueMask,
+ &Si->blue_pos, &Si->blue_size);
+ FindBits (Info->PixelInformation.ReservedMask,
+ &Si->rsvd_pos, &Si->rsvd_size);
+ Si->lfb_depth = Si->red_size + Si->green_size +
+ Si->blue_size + Si->rsvd_size;
+ Si->lfb_linelength = (UINT16) ((Info->PixelsPerScanLine * Si->lfb_depth) / 8);
+ } else {
+ Si->lfb_depth = 4;
+ Si->red_size = 0;
+ Si->red_pos = 0;
+ Si->green_size = 0;
+ Si->green_pos = 0;
+ Si->blue_size = 0;
+ Si->blue_pos = 0;
+ Si->rsvd_size = 0;
+ Si->rsvd_pos = 0;
+ Si->lfb_linelength = Si->lfb_width / 2;
+ }
+
+ return Status;
+}
+/*
+ Get graph-related parameters.
+
+ @param Si A pointer to the SCREEN_INFO struct.
+
+ @retval VOID
+ */
+EFI_STATUS
+SetupGraphics (
+ IN OUT SCREEN_INFO *si
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
+
+ ZeroMem ((VOID*)si, sizeof (SCREEN_INFO));
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiGraphicsOutputProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID*) &Gop
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = SetupGraphicsFromGop (si, Gop);
+ if (!EFI_ERROR (Status)) {
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+ }
+ }
+ FreePool (HandleBuffer);
+ }
+ return EFI_NOT_FOUND;
+}
+/*
+ Initialize screen information.
+
+ @param Bpi A pointer to the BootParamsInterface struct.
+ @param si A pointer to the SCREEN_INFO struct.
+
+ @retval VOID
+ */
+VOID
+EFIAPI
+InitScreenInfo (
+ IN BootParamsInterface *Bpi,
+ OUT SINFO *si
+ )
+{
+
+// UINTN Addr;
+ UINT8 Data[8] = {'S', 'I', 'N', 'F', 'O'};
+
+ SetMem (&si->Header, sizeof (EXT_LIST), 0);
+
+ CopyMem (&si->Header.Signature, Data, sizeof (UINT64));
+ si->Header.Revision = 0;
+ si->Header.Length = sizeof (SINFO);
+
+ SetupGraphics (&si->si);
+ AddToList (Bpi, &si->Header);
+}
+/*
+ Initialize the boot parameter interface.
+
+ @param Bpi A pointer to the BootParamsInterface struct.
+ @param SystemTable A pointer to the EFI_SYSTEM_TABLE struct.
+
+ @retval VOID
+ */
+VOID
+EFIAPI
+InitializeBpi (
+ IN BootParamsInterface *Bpi,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ DEBUG ((DEBUG_INFO, "New BPI addr: 0x%llx\n", (UINTN)Bpi));
+ UINT8 Data[8] = {'B', 'P', 'I', '0', '1', '0', '0', '1'};
+ CopyMem (&Bpi->Signature, Data, sizeof (UINT64));
+ Bpi->SystemTable = SystemTable;
+ Bpi->ExtList = NULL;
+}
+/*
+ Setup the boot parameter.
+
+ @param VOID
+
+ @retval EFI_SUCCESS The boot parameter was established successfully.
+ @retval EFI_INVALID_PARAMETER Input GUID is NULL.
+ @retval EFI_NOT_FOUND Attempted to delete non-existant entry
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available
+ */
+EFI_STATUS
+EFIAPI
+SetBootParams (VOID)
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ VOID *BufferAddress;
+ BootParamsInterface *Bpi;
+ MEM_MAP *MemMap;
+ SINFO *si;
+ EFI_SYSTEM_TABLE *SystemTable;
+
+ SystemTable = gST;
+ Size = sizeof (BootParamsInterface);
+ Size += sizeof (MEM_MAP);
+ Size += sizeof (SINFO);
+
+ Status = SystemTable->BootServices->AllocatePool (
+ EfiRuntimeServicesData,
+ Size,
+ &BufferAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (BufferAddress, Size);
+ Bpi = (BootParamsInterface *) BufferAddress;
+ InitializeBpi (Bpi, SystemTable);
+
+ MemMap = (MEM_MAP *) (Bpi + 1);
+ InitMemMap (Bpi, MemMap);
+
+ si = (SINFO*) (MemMap + 1);
+ InitScreenInfo (Bpi, si);
+
+#ifdef DEBUG_BPI
+ ShowList (Bpi);
+#endif
+ Status = SystemTable->BootServices->InstallConfigurationTable (
+ &gEfiLoongsonBootparamsTableGuid,
+ Bpi
+ );
+
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.inf
new file mode 100644
index 0000000000..c00a2e24fb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.inf
@@ -0,0 +1,38 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BpiLib
+ FILE_GUID = e15244d6-6df0-485f-9deb-190e21c57020
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BpiLib
+
+[Sources]
+ Bpi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Pcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+
+[Guids]
+ gEfiLoongsonBootparamsTableGuid ## SOMETIMES_PRODUCES ## SystemTable
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (4 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib xianglai
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Read the memory map information through the QemuFwCfg interface,
then build the page table through the memory map information,
and finally enable Mmu.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LoongArchQemuPkg/Include/Library/MmuLib.h | 85 ++
.../LoongArchQemuPkg/Library/MmuLib/Mmu.S | 35 +
.../Library/MmuLib/MmuBaseLib.inf | 35 +
.../Library/MmuLib/MmuBaseLibPei.inf | 45 +
.../Library/MmuLib/MmuLibCore.c | 790 ++++++++++++++++++
.../Library/MmuLib/MmuLibCore.h | 39 +
.../Library/MmuLib/MmuLibCorePei.c | 237 ++++++
.../LoongArchQemuPkg/Library/MmuLib/mmu.h | 101 +++
.../LoongArchQemuPkg/Library/MmuLib/page.h | 267 ++++++
.../LoongArchQemuPkg/Library/MmuLib/pte.h | 57 ++
10 files changed, 1691 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
new file mode 100644
index 0000000000..6c501eca07
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/MmuLib.h
@@ -0,0 +1,85 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - EXC - execute
+**/
+#ifndef MMU_LIB_H_
+#define MMU_LIB_H_
+/**
+ write operation is performed Count times from the first element of Buffer.
+Convert EFI Attributes to Loongarch Attributes.
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+ IN UINTN EfiAttributes
+ );
+
+/**
+ Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+ @param[in] BaseAddress To find the base address of the memory region.
+ @param[in] EndAddress To find the end address of the memory region.
+ @param[out] RegionLength The length of the memory region found.
+ @param[out] RegionAttributes Properties of the memory region found.
+
+ @retval EFI_SUCCESS The corresponding memory area was successfully found
+ EFI_NOT_FOUND No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+ IN UINTN BaseAddress,
+ IN UINTN EndAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ );
+
+/**
+ Sets the Attributes of the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+ @param[in] Attributes The Attributes to be set.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes
+ );
+
+/**
+ Sets the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ );
+/**
+ Create a page table and initialize the MMU.
+
+ @param[] VOID
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+ConfigureMmu (
+ VOID
+ );
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
new file mode 100644
index 0000000000..a697b54e65
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/Mmu.S
@@ -0,0 +1,35 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#-----------------------------------------------------------------------------
+
+#ifndef _KERNEL
+#define _KERNEL
+#endif
+
+#include "Library/Cpu.h"
+#include "LoongArchAsmMacro.h"
+
+# Query the page table.
+#
+# @param VOID
+#
+# @retval VOID
+ASM_FUNC(HandleTlbRefill)
+ csrwr T0, LOONGARCH_CSR_TLBRSAVE
+ csrrd T0, LOONGARCH_CSR_PGD
+ lddir T0, T0, 3 #Put pud BaseAddress into T0
+ lddir T0, T0, 2 #Put pmd BaseAddress into T0
+ lddir T0, T0, 1 #Put pte BaseAddress into T0
+ ldpte T0, 0
+ ldpte T0, 1
+ tlbfill
+ csrrd T0, LOONGARCH_CSR_TLBRSAVE
+ ertn
+.globl HandleTlbRefillEnd
+HandleTlbRefillEnd:
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
new file mode 100644
index 0000000000..d8cfe6776e
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
@@ -0,0 +1,35 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MmuBaseLib
+ FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70be
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmuLib
+
+ CONSTRUCTOR = MmuInitialize
+[Sources.common]
+ MmuLibCore.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[PCD]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
new file mode 100644
index 0000000000..20e50218af
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
@@ -0,0 +1,45 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MmuPeiLib
+ FILE_GUID = da8f0232-fb14-42f0-922c-63104d2c70bd
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MmuLib | SEC PEIM
+
+[Sources.common]
+ MmuLibCorePei.c
+ Mmu.S
+ MmuLibCore.h
+ MmuLibCore.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ OvmfPkg/OvmfPkg.dec
+
+[PCD]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+
+[FixedPcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom
+
+[LibraryClasses]
+ MemoryAllocationLib
+ PcdLib
+ DebugLib
+ QemuFwCfgLib
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
new file mode 100644
index 0000000000..8039955bb4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.c
@@ -0,0 +1,790 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Pgd or Pgd or PGD - Page Global Directory
+ - Pud or Pud or PUD - Page Upper Directory
+ - Pmd or Pmd or PMD - Page Middle Directory
+ - Pte or pte or PTE - Page Table Entry
+ - Val or VAL or val - Value
+ - Dir - Directory
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+
+BOOLEAN mMmuInited = FALSE;
+/**
+ Check to see if mmu successfully initializes.
+
+ @param VOID.
+
+ @retval TRUE Initialization has been completed.
+ FALSE Initialization did not complete.
+**/
+BOOLEAN
+MmuIsInit (VOID) {
+ if ((mMmuInited == TRUE) ||
+ (PcdGet64 (PcdSwapPageDir) != 0)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Iterates through the page directory to initialize it.
+
+ @param Dst A pointer to the directory of the page to initialize.
+ @param Num The number of page directories to initialize.
+ @param Src A pointer to the data used to initialize the page directory.
+
+ @retval VOID.
+**/
+VOID
+PageDirInit (
+ IN VOID *Dst,
+ IN UINTN Num,
+ IN VOID *Src
+ )
+{
+ UINTN *Ptr;
+ UINTN *End;
+ UINTN Entry;
+
+ Entry = (UINTN)Src;
+ Ptr = (UINTN *)Dst;
+ End = Ptr + Num;
+
+ for ( ;Ptr < End; Ptr++) {
+ *Ptr = Entry;
+ }
+
+ return ;
+}
+/**
+ Gets the virtual address corresponding to the page global directory table entry.
+
+ @param Address the virtual address for the table entry.
+
+ @retval PGD A pointer to get the table item.
+**/
+PGD *
+PgdOffset (
+ IN UINTN Address
+ )
+{
+ return ((PGD *)PcdGet64 (PcdSwapPageDir)) + PGD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page upper directory table entry.
+
+ @param Pgd A pointer to a page global directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PUD A pointer to get the table item.
+**/
+PUD *
+PudOffset (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ UINTN PgdVal = (UINTN)PGD_VAL (*Pgd);
+ return (PUD *)PgdVal + PUD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page middle directory table entry.
+
+ @param Pud A pointer to a page upper directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PMD A pointer to get the table item.
+**/
+PMD *
+PmdOffset (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ UINTN PudVal = PUD_VAL (*Pud);
+ return (PMD *)PudVal + PMD_INDEX (Address);
+}
+/**
+ Gets the virtual address corresponding to the page table entry.
+
+ @param Pmd A pointer to a page middle directory table entry.
+ @param Address the virtual address for the table entry.
+
+ @retval PTE A pointer to get the table item.
+**/
+PTE *
+PteOffset (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ UINTN PmdVal = (UINTN)PMD_VAL (*Pmd);
+ return (PTE *)PmdVal + PTE_INDEX (Address);
+}
+
+/**
+ Sets the value of the page table entry.
+
+ @param Pte A pointer to a page table entry.
+ @param PteVal The value of the page table entry to set.
+
+ @retval VOID
+**/
+VOID
+SetPte (
+ IN PTE *Pte,
+ IN PTE PteVal
+ )
+{
+ *Pte = PteVal;
+}
+/**
+ Sets the value of the page global directory.
+
+ @param Pgd A pointer to a page global directory.
+ @param Pud The value of the page global directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPgd (
+ IN PGD *Pgd,
+ IN PUD *Pud
+ )
+{
+ *Pgd = (PGD) {((UINTN)Pud)};
+}
+
+/**
+ Sets the value of the page upper directory.
+
+ @param Pud A pointer to a page upper directory.
+ @param Pmd The value of the page upper directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPud (
+ IN PUD *Pud,
+ IN PMD *Pmd
+ )
+{
+ *Pud = (PUD) {((UINTN)Pmd)};
+}
+
+/**
+ Sets the value of the page middle directory.
+
+ @param Pmd A pointer to a page middle directory.
+ @param Pte The value of the page middle directory to set.
+
+ @retval VOID
+**/
+VOID
+SetPmd (
+ IN PMD *Pmd,
+ IN PTE *Pte
+ )
+{
+ *Pmd = (PMD) {((UINTN)Pte)};
+}
+/**
+ Free up memory space occupied by page tables.
+
+ @param Pte A pointer to the page table.
+
+ @retval VOID
+**/
+VOID
+PteFree (
+ IN PTE *Pte
+ )
+{
+ FreePages ((VOID *)Pte, 1);
+}
+/**
+ Free up memory space occupied by page middle directory.
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval VOID
+**/
+VOID
+PmdFree (
+ IN PMD *Pmd
+ )
+{
+ FreePages ((VOID *)Pmd, 1);
+}
+/**
+ Free up memory space occupied by page upper directory.
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval VOID
+**/
+VOID
+PudFree (
+ IN PUD *Pud
+ )
+{
+ FreePages ((VOID *)Pud, 1);
+}
+/**
+ Requests the memory space required for the page upper directory,
+ initializes it, and places it in the specified page global directory
+
+ @param Pgd A pointer to the page global directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PudAlloc (
+ IN PGD *Pgd
+ )
+{
+ PUD *Pud = (PUD *) AllocatePages (1);
+ if (!Pud) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pud, ENTRYS_PER_PUD, (VOID *)PcdGet64 (PcdInvalidPmd));
+
+ if (pgd_none (*Pgd)) {
+ SetPgd (Pgd, Pud);
+ } else { /* Another has populated it */
+ PudFree (Pud);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page middle directory,
+ initializes it, and places it in the specified page upper directory
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+EFI_STATUS
+PmdAlloc (
+ IN PUD *Pud
+ )
+{
+ PMD *Pmd;
+
+ Pmd = (PMD *) AllocatePages (1);
+ if (!Pmd) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PageDirInit ((VOID *)Pmd, ENTRYS_PER_PMD, (VOID *)PcdGet64 (PcdInvalidPte));
+
+ if (pud_none (*Pud)) {
+ SetPud (Pud, Pmd);
+ } else {/* Another has populated it */
+ PmdFree (Pmd);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page table,
+ initializes it, and places it in the specified page middle directory
+
+ @param Pmd A pointer to the page middle directory.
+
+ @retval EFI_SUCCESS Memory request successful.
+ @retval EFI_OUT_OF_RESOURCES Resource exhaustion cannot be requested to memory.
+**/
+INTN
+PteAlloc (
+ IN PMD *Pmd
+ )
+{
+ PTE *Pte;
+
+ Pte = (PTE *) AllocatePages (1);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pte = ZeroMem (Pte, EFI_PAGE_SIZE);
+
+ if (pmd_none (*Pmd)) {
+ SetPmd (Pmd, Pte);
+ } else { /* Another has populated it */
+ PteFree (Pte);
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Requests the memory space required for the page upper directory,
+ initializes it, and places it in the specified page global directory,
+ and get the page upper directory entry corresponding to the virtual address
+
+ @param Pgd A pointer to the page global directory.
+
+ @retval Gets the page upper directory entry
+**/
+PUD *
+PudAllocGet (
+ IN PGD *Pgd,
+ IN UINTN Address
+ )
+{
+ return ((pgd_none (*(Pgd)) && PudAlloc (Pgd)) ?
+ NULL : PudOffset (Pgd, Address));
+}
+/**
+ Requests the memory space required for the page middle directory,
+ initializes it, and places it in the specified page upper directory,
+ and get the page middle directory entry corresponding to the virtual address
+
+ @param Pud A pointer to the page upper directory.
+
+ @retval Gets the page middle directory entry
+**/
+PMD *
+PmdAllocGet (
+ IN PUD *Pud,
+ IN UINTN Address
+ )
+{
+ PMD * ret = (pud_none (*Pud) && PmdAlloc (Pud))?
+ NULL: PmdOffset (Pud, Address);
+ DEBUG ((DEBUG_VERBOSE, "%a %d PudVal %p PmdOffset %p PMD_INDEX %p .\n", __func__, __LINE__,
+ Pud->PudVal, PmdOffset (Pud, Address), PMD_INDEX (Address) ));
+
+ return ret;
+}
+/**
+ Requests the memory space required for the page table,
+ initializes it, and places it in the specified page middle directory,
+ and get the page table entry corresponding to the virtual address
+
+ @param Pmd A pointer to the page upper directory.
+
+ @retval Gets the page table entry
+**/
+PTE *
+PteAllocGet (
+ IN PMD *Pmd,
+ IN UINTN Address
+ )
+{
+ return (pmd_none (*Pmd) && PteAlloc (Pmd))?
+ NULL: PteOffset (Pmd, Address);
+}
+/**
+ 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;
+ UINTN Num = 0;
+ Pte = PteAllocGet (Pmd, Address);
+ if (!Pte) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d Address %p PGD_INDEX %p PGD_INDEX %p PMD_INDEX %p PTE_INDEX %p MAKE_PTE %p Num %p \n",
+ __func__, __LINE__, Address, PGD_INDEX (Address), PGD_INDEX (Address), PMD_INDEX (Address),
+ PTE_INDEX (Address), MAKE_PTE (Address, Attributes), Num));
+ SetPte (Pte, MAKE_PTE (Address, Attributes));
+ Num++;
+ } while (Pte++, Address += EFI_PAGE_SIZE, Address != End);
+
+ return EFI_SUCCESS;
+}
+/**
+ Establishes a page middle directory based on the specified memory region.
+
+ @param Pud A pointer to the page upper directory.
+ @param Address The memory space start address.
+ @param End The end address of the memory space.
+ @param Attributes Memory space Attributes.
+
+ @retval EFI_SUCCESS The page middle directory was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Page middle directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPmdRange (
+ IN PUD *Pud,
+ IN UINTN Address,
+ IN UINTN End,
+ IN UINTN Attributes
+ )
+{
+ PMD *Pmd;
+ UINTN Next;
+ UINTN Num = 0;
+ UINTN AddressStart_HugePage;
+ UINTN AddressEnd_HugePage;
+
+ Pmd = PmdAllocGet (Pud, Address);
+ if (!Pmd) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ Next = PMD_ADDRESS_END (Address, End);
+ Num++;
+ if (((Address & (~PMD_MASK)) == 0) &&
+ ((Next & (~PMD_MASK)) == 0))
+ {
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d Address %p PGD_INDEX %p PUD_INDEX %p PMD_INDEX %p MAKE_HUGE_PTE %p Num %p \n",
+ __func__, __LINE__, Address, PGD_INDEX (Address), PUD_INDEX (Address), PMD_INDEX (Address),
+ MAKE_HUGE_PTE (Address, Attributes), Num));
+ SetPmd (Pmd, (PTE *)MAKE_HUGE_PTE (Address, Attributes));
+ } else {
+ if ((pmd_none (*Pmd)) ||
+ (!pmd_none (*Pmd) &&
+ IS_HUGE_PAGE (Pmd->PmdVal)))
+ {
+ if (MemoryMapPteRange (Pmd, Address, Next, Attributes)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ AddressStart_HugePage = Address & PMD_MASK;
+ AddressEnd_HugePage = AddressStart_HugePage + HUGE_PAGE_SIZE;
+ if (MemoryMapPteRange (Pmd, AddressStart_HugePage, AddressEnd_HugePage, Attributes)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ }
+ } while (Pmd++, Address = Next, Address != End);
+
+ return 0;
+}
+/**
+ Establishes a page upper directory based on the specified memory region.
+
+ @param Pgd A pointer to the page global directory.
+ @param Address The memory space start address.
+ @param End The end address of the memory space.
+ @param Attributes Memory space Attributes.
+
+ @retval EFI_SUCCESS The page upper directory was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Page upper directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPudRange (
+ IN PGD *Pgd,
+ IN UINTN Address,
+ IN UINTN End,
+ IN UINTN Attributes
+ )
+{
+ PUD *Pud;
+ UINTN Next;
+
+ Pud = PudAllocGet (Pgd, Address);
+ if (!Pud) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ Next = PUD_ADDRESS_END (Address, End);
+ if (MemoryMapPmdRange (Pud, Address, Next, Attributes)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } while (Pud++, Address = Next, Address != End);
+ return EFI_SUCCESS;
+}
+/**
+ Establishes a page global directory based on the specified memory region.
+
+ @param Start The memory space start address.
+ @param End The end address of the memory space.
+ @param Attributes Memory space Attributes.
+
+ @retval EFI_SUCCESS The page global directory was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Page global directory establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+MemoryMapPageRange (
+ IN UINTN Start,
+ IN UINTN End,
+ IN UINTN Attributes
+ )
+{
+ PGD *Pgd;
+ UINTN Next;
+ UINTN Address = Start;
+ EFI_STATUS Err;
+
+ Pgd = PgdOffset (Address);
+ do {
+ Next = PGD_ADDRESS_END (Address, End);
+ Err = MemoryMapPudRange (Pgd, Address, Next, Attributes);
+ if (Err) {
+ return Err;
+ }
+ } while (Pgd++, Address = Next, Address != End);
+
+ return EFI_SUCCESS;
+}
+/**
+ Gets the physical address of the page table entry corresponding to the specified virtual address.
+
+ @param Address the corresponding virtual address of the page table entry.
+
+ @retval A pointer to the page table entry.
+ @retval NULL
+**/
+PTE *
+GetPteAddress (
+ IN UINTN Address
+ )
+{
+ PGD *Pgd;
+ PUD *Pud;
+ PMD *Pmd;
+
+ Pgd = PgdOffset (Address);
+
+ if (pgd_none (*Pgd)) {
+ return NULL;
+ }
+
+ Pud = PudOffset (Pgd, Address);
+
+ if (pud_none (*Pud)) {
+ return NULL;
+ }
+
+ Pmd = PmdOffset (Pud, Address);
+ if (pmd_none (*Pmd)) {
+ return NULL;
+ }
+
+ if (IS_HUGE_PAGE (Pmd->PmdVal)) {
+ return ((PTE *)Pmd);
+ }
+
+ return PteOffset (Pmd, Address);
+}
+/**
+ Page tables are established from memory-mapped tables.
+
+ @param MemoryRegion A pointer to a memory-mapped table entry.
+
+ @retval EFI_SUCCESS The page table was created successfully.
+ @retval EFI_OUT_OF_RESOURCES Page table establishment failed due to resource exhaustion.
+**/
+EFI_STATUS
+FillTranslationTable (
+ IN MEMORY_REGION_DESCRIPTOR *MemoryRegion
+ )
+{
+ return MemoryMapPageRange (MemoryRegion->VirtualBase,
+ (MemoryRegion->Length + MemoryRegion->VirtualBase),
+ MemoryRegion->Attributes);
+}
+
+/**
+ write operation is performed Count times from the first element of Buffer.
+Convert EFI Attributes to Loongarch Attributes.
+ @param[in] EfiAttributes Efi Attributes.
+
+ @retval LoongArch Attributes.
+**/
+UINTN
+EfiAttributeToLoongArchAttribute (
+ IN UINTN EfiAttributes
+ )
+{
+ UINTN LoongArchAttributes = PAGE_VALID | PAGE_DIRTY | CACHE_CC;
+ switch (EfiAttributes & EFI_MEMORY_CACHETYPE_MASK) {
+ case EFI_MEMORY_UC:
+ LoongArchAttributes |= CACHE_SUC;
+ break;
+ case EFI_MEMORY_WC:
+ case EFI_MEMORY_WT:
+ case EFI_MEMORY_WB:
+ LoongArchAttributes |= CACHE_CC;
+ break;
+ default :
+ LoongArchAttributes |= CACHE_CC;
+ break;
+ }
+
+ // Write protection attributes
+ if ((EfiAttributes & EFI_MEMORY_RO) != 0) {
+ LoongArchAttributes &= ~PAGE_DIRTY;
+ }
+
+ //eXecute protection attribute
+ if ((EfiAttributes & EFI_MEMORY_XP) != 0) {
+ LoongArchAttributes |= PAGE_NO_EXEC;
+ }
+
+ return LoongArchAttributes;
+}
+
+/**
+ Finds the length and memory properties of the memory region corresponding to the specified base address.
+
+ @param[in] BaseAddress To find the base address of the memory region.
+ @param[in] EndAddress To find the end address of the memory region.
+ @param[out] RegionLength The length of the memory region found.
+ @param[out] RegionAttributes Properties of the memory region found.
+
+ @retval EFI_SUCCESS The corresponding memory area was successfully found
+ EFI_NOT_FOUND No memory area found
+**/
+EFI_STATUS
+GetLoongArchMemoryRegion (
+ IN UINTN BaseAddress,
+ IN UINTN EndAddress,
+ OUT UINTN *RegionLength,
+ OUT UINTN *RegionAttributes
+ )
+{
+ PTE *Pte;
+ UINTN Attributes;
+ UINTN AttributesTmp;
+ UINTN MaxAddress;
+ MaxAddress = LShiftU64 (1ULL, MAX_VA_BITS) - 1;
+ Pte = GetPteAddress (BaseAddress);
+
+ if (!MmuIsInit ()) {
+ return EFI_SUCCESS;
+ }
+ if (Pte == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ Attributes = GET_PAGE_ATTRIBUTES (*Pte);
+ if (IS_HUGE_PAGE (Pte->PteVal)) {
+ *RegionAttributes = Attributes & (~(PAGE_HUGE));
+ *RegionLength += HUGE_PAGE_SIZE;
+ } else {
+ *RegionLength += EFI_PAGE_SIZE;
+ *RegionAttributes = Attributes;
+ }
+
+ while (BaseAddress <= MaxAddress) {
+ Pte = GetPteAddress (BaseAddress);
+ if (Pte == NULL) {
+ return EFI_SUCCESS;
+ }
+ AttributesTmp = GET_PAGE_ATTRIBUTES (*Pte);
+ if (IS_HUGE_PAGE (Pte->PteVal)) {
+ if (AttributesTmp == Attributes) {
+ *RegionLength += HUGE_PAGE_SIZE;
+ }
+ BaseAddress += HUGE_PAGE_SIZE;
+ } else {
+ if (AttributesTmp == Attributes) {
+ *RegionLength += EFI_PAGE_SIZE;
+ }
+ BaseAddress += EFI_PAGE_SIZE;
+ }
+
+ if (BaseAddress > EndAddress) {
+ break;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the Attributes of the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+ @param[in] Attributes The Attributes to be set.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+
+**/
+EFI_STATUS
+LoongArchSetMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length,
+ IN UINTN Attributes
+ )
+{
+#if 0
+ if (!MmuIsInit ()) {
+ return EFI_SUCCESS;
+ }
+ PGPROT_VAL (Attributes) = EfiAttributeToLoongArchAttribute (Attributes);
+ DEBUG ((DEBUG_VERBOSE, "%a %d %p %p %p.\n", __func__, __LINE__, BaseAddress , Length, Attributes));
+ MemoryMapPageRange (BaseAddress, BaseAddress + Length, Attributes);
+#endif
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the non-executable Attributes for the specified memory region
+
+ @param[in] BaseAddress The base address of the memory region to set the Attributes.
+ @param[in] Length The length of the memory region to set the Attributes.
+
+ @retval EFI_SUCCESS The Attributes was set successfully
+**/
+EFI_STATUS
+LoongArchSetMemoryRegionNoExec (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINTN Length
+ )
+{
+ if (MmuIsInit ()) {
+ Length = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Length));
+ LoongArchSetMemoryAttributes (BaseAddress, Length, EFI_MEMORY_XP);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Check to see if mmu successfully initializes and saves the result.
+
+ @param VOID.
+
+ @retval EFI_SUCCESS Initialization succeeded.
+**/
+EFI_STATUS
+MmuInitialize (VOID)
+{
+ if (PcdGet64 (PcdSwapPageDir) != 0) {
+ mMmuInited = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
new file mode 100644
index 0000000000..e9f294b356
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCore.h
@@ -0,0 +1,39 @@
+/** @file
+
+ Copyright (c) 2021 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
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
new file mode 100644
index 0000000000..84269e86fb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuLibCorePei.c
@@ -0,0 +1,237 @@
+/** @file
+ Platform PEI driver
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - FwCfg - Firmeware Config
+ - Tlb - Translation Lookaside Buffer
+**/
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/Cpu.h"
+#include "pte.h"
+#include "page.h"
+#include "mmu.h"
+#include <Library/Bpi.h>
+#include <Library/QemuFwCfgLib.h>
+#include "MmuLibCore.h"
+
+
+/**
+ Return the Virtual Memory Map of your platform
+
+ This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
+ on your platform.
+
+ @param[out] VirtualMemoryMap Array of MEMORY_REGION_DESCRIPTOR
+ describing a Physical-to-Virtual Memory
+ mapping. This array must be ended by a
+ zero-filled entry. The allocated memory
+ will not be freed.
+
+**/
+VOID
+GetMemoryMapFromFwCfg (
+ OUT MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
+ )
+{
+
+ EFI_STATUS Status;
+ FIRMWARE_CONFIG_ITEM FwCfgItem;
+ UINTN FwCfgSize;
+ LOONGARCH_MEMMAP_ENTRY MemoryMapEntry;
+ LOONGARCH_MEMMAP_ENTRY *StartEntry;
+ LOONGARCH_MEMMAP_ENTRY *pEntry;
+ UINTN Processed;
+ MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
+ UINTN Index = 0;
+ ASSERT (VirtualMemoryMap != NULL);
+
+ VirtualMemoryTable = AllocatePool (
+ sizeof (MEMORY_REGION_DESCRIPTOR) *
+ MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+ );
+ VirtualMemoryTable[Index].PhysicalBase = 0x10000000;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = 0x80000000;
+ VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY;
+ ++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;
+ }
+
+ VirtualMemoryTable[Index].PhysicalBase = pEntry->BaseAddr;
+ VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
+ VirtualMemoryTable[Index].Length = pEntry->Length;
+ VirtualMemoryTable[Index].Attributes = PAGE_VALID | PAGE_USER | CACHE_CC | PAGE_DIRTY;
+ ++Index;
+ }
+
+ FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize));
+ // End of Table
+ ZeroMem (&VirtualMemoryTable[Index], sizeof (MEMORY_REGION_DESCRIPTOR));
+ *VirtualMemoryMap = VirtualMemoryTable;
+ return ;
+}
+
+/**
+ Create a page table and initialize the MMU.
+
+ @param[] VOID
+
+ @retval VOID
+**/
+EFIAPI
+VOID
+ConfigureMmu (VOID)
+{
+ PGD *SwapperPageDir = NULL;
+ PGD *InvalidPgd = NULL;
+ PUD *InvalidPudTable = NULL;
+ PMD *InvalidPmdTable = NULL;
+ PTE *InvalidPteTable = NULL;
+ MEMORY_REGION_DESCRIPTOR *MemoryTable = NULL;
+ RETURN_STATUS PcdStatus;
+ UINTN PgdShift = PGD_SHIFT;
+ UINTN PgdWide = PGD_WIDE;
+ UINTN PudShift = PUD_SHIFT;
+ UINTN PudWide = PUD_WIDE;
+ UINTN PmdShift = PMD_SHIFT;
+ UINTN PmdWide = PMD_WIDE;
+ UINTN PteShift = PTE_SHIFT;
+ UINTN PteWide = PTE_WIDE;
+ UINTN PageEnable = 1 << 4;
+ VOID *TlbReEntry;
+ UINTN PageSize;
+
+ SwapperPageDir = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ InvalidPgd = AllocatePages (EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ InvalidPudTable = AllocatePages (EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+ InvalidPmdTable = AllocatePages (EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+ InvalidPteTable = AllocatePages (EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+ ZeroMem (InvalidPteTable, PTE_TABLE_SIZE);
+
+ if ((!InvalidPgd) ||
+ (!InvalidPudTable) ||
+ (!InvalidPmdTable) ||
+ (!InvalidPteTable))
+ {
+ goto FreeTranslationTable;
+ }
+
+ /*pgd init*/
+ PageDirInit (SwapperPageDir , ENTRYS_PER_PGD, InvalidPudTable);
+ /*pgd init*/
+ PageDirInit (InvalidPgd, ENTRYS_PER_PGD, InvalidPudTable);
+ /*pud init*/
+ PageDirInit (InvalidPudTable, ENTRYS_PER_PUD, InvalidPmdTable);
+ /*pmd init*/
+ PageDirInit (InvalidPmdTable, ENTRYS_PER_PMD, InvalidPteTable);
+ GetMemoryMapFromFwCfg (&MemoryTable);
+
+ PcdStatus |= PcdSet64S (PcdSwapPageDir, (UINTN)SwapperPageDir);
+ PcdStatus |= PcdSet64S (PcdInvalidPgd, (UINTN)InvalidPgd);
+ PcdStatus |= PcdSet64S (PcdInvalidPud, (UINTN)InvalidPudTable);
+ PcdStatus |= PcdSet64S (PcdInvalidPmd, (UINTN)InvalidPmdTable);
+ PcdStatus |= PcdSet64S (PcdInvalidPte, (UINTN)InvalidPteTable);
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ while (MemoryTable->Length != 0) {
+ DEBUG ((DEBUG_VERBOSE, "%a %d VirtualBase %p VirtualEnd %p Attributes %p .\n", __func__, __LINE__,
+ MemoryTable->VirtualBase,
+ (MemoryTable->Length + MemoryTable->VirtualBase),
+ MemoryTable->Attributes));
+
+ PcdStatus = FillTranslationTable (MemoryTable);
+ if (EFI_ERROR (PcdStatus)) {
+ goto FreeTranslationTable;
+ }
+ MemoryTable++;
+ }
+
+ /*set page size*/
+ WRITE_CSR_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ WRITE_CSR_STLB_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ WRITE_CSR_TLBREFILL_PAGE_SIZE (DEFAULT_PAGE_SIZE);
+ READ_CSR_PAGE_SIZE (PageSize);
+ if (PageSize != DEFAULT_PAGE_SIZE) {
+ goto FreeTranslationTable;
+ }
+
+ TlbReEntry = AllocatePages (1);
+ if (TlbReEntry == NULL) {
+ goto FreeTranslationTable;
+ }
+ CopyMem ((char *)TlbReEntry, HandleTlbRefill, (HandleTlbRefillEnd - HandleTlbRefill));
+ SET_REFILL_TLBBASE ((UINTN)HandleTlbRefill);
+
+ DEBUG ((DEBUG_VERBOSE,
+ "%a %d PteShift %d PteWide %d PmdShift %d PmdWide %d PudShift %d PudWide %d PgdShift %d PgdWide %d.\n",
+ __func__, __LINE__,
+ PteShift, PteWide, PmdShift, PmdWide,PudShift, PudWide, PgdShift, PgdWide));
+
+ LOONGARCH_CSR_WRITEQ (PteShift | PteWide << 5 | PmdShift << 10 | PmdWide << 15 | PudShift << 20 | PudWide << 25,
+ LOONGARCH_CSR_PWCTL0);
+ LOONGARCH_CSR_WRITEQ (PgdShift | PgdWide << 6, LOONGARCH_CSR_PWCTL1);
+ LOONGARCH_CSR_WRITEQ ((UINTN)SwapperPageDir, LOONGARCH_CSR_PGDL);
+ LOONGARCH_CSR_WRITEQ ((UINTN)InvalidPgd, LOONGARCH_CSR_PGDH);
+
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu Start PageBassAddress %p.\n", __func__, __LINE__, SwapperPageDir));
+ LOONGARCH_CSR_XCHGQ ( PageEnable, 1 << 4, LOONGARCH_CSR_CRMD);
+ DEBUG ((DEBUG_INFO, "%a %d Enable Mmu End.\n", __func__, __LINE__));
+
+ return ;
+
+FreeTranslationTable:
+ if (SwapperPageDir) {
+ FreePages (SwapperPageDir, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ if (InvalidPgd) {
+ FreePages (InvalidPgd, EFI_SIZE_TO_PAGES (PGD_TABLE_SIZE));
+ }
+
+ if (InvalidPudTable) {
+ FreePages (InvalidPudTable, EFI_SIZE_TO_PAGES (PUD_TABLE_SIZE));
+ }
+
+ if (InvalidPmdTable) {
+ FreePages (InvalidPmdTable, EFI_SIZE_TO_PAGES (PMD_TABLE_SIZE));
+ }
+
+ if (InvalidPteTable) {
+ FreePages (InvalidPteTable, EFI_SIZE_TO_PAGES (PTE_TABLE_SIZE));
+ }
+
+ PcdSet64S (PcdSwapPageDir, (UINTN)0);
+ PcdSet64S (PcdInvalidPgd, (UINTN)0);
+ PcdSet64S (PcdInvalidPud, (UINTN)0);
+ PcdSet64S (PcdInvalidPmd, (UINTN)0);
+ PcdSet64S (PcdInvalidPte, (UINTN)0);
+
+ return ;
+}
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
new file mode 100644
index 0000000000..cd11f45dd4
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/mmu.h
@@ -0,0 +1,101 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Tlb or TLB - Translation Lookaside Buffer
+ - CSR - Cpu State Register
+ - PGDL - Page Global Directory Low
+ - PGDH - Page Global Directory High
+ - TLBIDX - TLB Index
+ - TLBREHI - TLB Refill Entry High
+ - PWCTL - Page Walk Control
+ - STLB - Singular Page Size TLB
+ - PS - Page Size
+**/
+#ifndef MMU_H_
+#define MMU_H_
+/*page size 4k*/
+#define DEFAULT_PAGE_SIZE 0x0c
+#define LOONGARCH_CSR_PGDL 0x19 /* Page table base address when VA[47] = 0 */
+#define LOONGARCH_CSR_PGDH 0x1a /* Page table base address when VA[47] = 1 */
+#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */
+#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */
+#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */
+#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */
+#define LOONGARCH_CSR_STLBPGSIZE 0x1e
+#define CSR_TLBIDX_SIZE_MASK 0x3f000000
+#define CSR_TLBIDX_PS_SHIFT 24
+#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT
+
+/*
+ Set Cpu Status Register STLB Page Size.
+
+ @param val Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_STLB_PAGE_SIZE(val) LOONGARCH_CSR_WRITEQ((val), LOONGARCH_CSR_STLBPGSIZE)
+/*
+ Set Cpu Status Register Page Size.
+
+ @param size Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBIDX_SIZE, CSR_TLBIDX_SIZE_MASK, LOONGARCH_CSR_TLBIDX)
+/*
+ Set Cpu Status Register TLBREFILL Page Size.
+
+ @param size Page Size.
+
+ @retval VOID
+ */
+#define WRITE_CSR_TLBREFILL_PAGE_SIZE(size) LOONGARCH_CSR_XCHGQ((size) << CSR_TLBREHI_PS_SHIFT, CSR_TLBREHI_PS, LOONGARCH_CSR_TLBREHI)
+/*
+ Set Cpu Status Register TLBREFILL Base Address.
+
+ @param BaseAddress the code base address of TLB refills .
+
+ @retval VOID
+ */
+#define SET_REFILL_TLBBASE(BaseAddress) LOONGARCH_CSR_WRITEQ((BaseAddress), LOONGARCH_CSR_TLBREBASE);
+/*
+ Get Cpu Status Register Page Size.
+
+ @param val Gets the page size.
+
+ @retval VOID
+ */
+#define READ_CSR_PAGE_SIZE(val) \
+{ \
+ LOONGARCH_CSR_READQ ((val), LOONGARCH_CSR_TLBIDX); \
+ (val) = ((val) & CSR_TLBIDX_SIZE_MASK) >> CSR_TLBIDX_SIZE; \
+}
+
+
+#define CSR_TLBREHI_PS_SHIFT 0
+#define CSR_TLBREHI_PS ((UINTN)(0x3f) << CSR_TLBREHI_PS_SHIFT)
+
+#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | \
+ EFI_MEMORY_WC | \
+ EFI_MEMORY_WT | \
+ EFI_MEMORY_WB | \
+ EFI_MEMORY_UCE \
+ )
+
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS PhysicalBase;
+ EFI_VIRTUAL_ADDRESS VirtualBase;
+ UINTN Length;
+ UINTN Attributes;
+} MEMORY_REGION_DESCRIPTOR;
+
+// The total number of descriptors, including the final "end-of-table" descriptor.
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128)
+
+extern CHAR8 HandleTlbRefill[], HandleTlbRefillEnd[];
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
new file mode 100644
index 0000000000..3773ddcd09
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/page.h
@@ -0,0 +1,267 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Pgd or Pgd or PGD - Page Global Directory
+ - Pud or Pud or PUD - Page Upper Directory
+ - Pmd or Pmd or PMD - Page Middle Directory
+ - Pte or pte or PTE - Page Table Entry
+ - Val or VAL or val - Value
+ - Dir - Directory
+**/
+#ifndef PAGE_H_
+#define PAGE_H_
+
+#define MAX_VA_BITS 47
+#define PGD_WIDE (8)
+#define PUD_WIDE (9)
+#define PMD_WIDE (9)
+#define PTE_WIDE (9)
+
+#define ENTRYS_PER_PGD (1 << PGD_WIDE)
+#define ENTRYS_PER_PUD (1 << PUD_WIDE)
+#define ENTRYS_PER_PMD (1 << PMD_WIDE)
+#define ENTRYS_PER_PTE (1 << PTE_WIDE)
+
+#define PGD_SHIFT (PUD_SHIFT + PUD_WIDE)
+#define PUD_SHIFT (PMD_SHIFT + PMD_WIDE)
+#define PMD_SHIFT (EFI_PAGE_SHIFT + PTE_WIDE)
+#define PTE_SHIFT (EFI_PAGE_SHIFT)
+
+#define PGD_SIZE (1UL << PGD_SHIFT)
+#define PUD_SIZE (1UL << PUD_SHIFT)
+#define PMD_SIZE (1UL << PMD_SHIFT)
+
+#define PGD_MASK (~(PGD_SIZE-1))
+#define PUD_MASK (~(PUD_SIZE-1))
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PAGE_MASK (~(EFI_PAGE_SIZE - 1)
+#define PFN_MASK (~(((UINTN)(1) << (EFI_PAGE_SHIFT)) - 1) & \
+ (((UINTN)(1) << (PAGE_PFN_END_SHIFT)) - 1))
+
+typedef struct { UINTN PgdVal; } PGD;
+typedef struct { UINTN PudVal; } PUD;
+typedef struct { UINTN PmdVal; } PMD;
+typedef struct { UINTN PteVal; } PTE;
+/**
+ Gets the value of the page global directory table entry.
+
+ @param x Page global directory struct variables.
+
+ @retval the value of the page global directory table entry.
+ **/
+#define PGD_VAL(x) ((x).PgdVal)
+/**
+ Gets the value of the page upper directory table entry.
+
+ @param x Page upper directory struct variables.
+
+ @retval the value of the page upper directory table entry.
+ **/
+#define PUD_VAL(x) ((x).PudVal)
+/**
+ Gets the value of the page middle directory table entry.
+
+ @param x Page middle directory struct variables.
+
+ @retval the value of the page middle directory table entry.
+ **/
+#define PMD_VAL(x) ((x).PmdVal)
+/**
+ Gets the value of the page table entry.
+
+ @param x Page table entry struct variables.
+
+ @retval the value of the page table entry.
+ **/
+#define PTE_VAL(x) ((x).PteVal)
+
+
+#define PGD_TABLE_SIZE (ENTRYS_PER_PGD * sizeof(PGD))
+#define PUD_TABLE_SIZE (ENTRYS_PER_PUD * sizeof(PUD))
+#define PMD_TABLE_SIZE (ENTRYS_PER_PMD * sizeof(PMD))
+#define PTE_TABLE_SIZE (ENTRYS_PER_PTE * sizeof(PTE))
+/**
+ Gets the physical address of the record in the page table entry.
+
+ @param x Page table entry struct variables.
+
+ @retval the value of the physical address.
+ **/
+#define GET_PAGE_ATTRIBUTES(x) (UINTN) {(PTE_VAL(x) & ~PFN_MASK)}
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the global page directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PGD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PGD_SIZE) & PGD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the page upper directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PUD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PUD_SIZE) & PUD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Gets the virtual address of the next block of the specified virtual address
+ that is aligned with the size of the page middle directory mapping.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the specified virtual address of the next block.
+ **/
+#define PMD_ADDRESS_END(Address, End) \
+({ UINTN Boundary = ((Address) + PMD_SIZE) & PMD_MASK; \
+ (Boundary - 1 < (End) - 1)? Boundary: (End); \
+})
+/**
+ Get Specifies the virtual address corresponding to the index of the page global directory table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page global directory table entry.
+ **/
+#define PGD_INDEX(Address) (((Address) >> PGD_SHIFT) & (ENTRYS_PER_PGD-1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page upper directory table entry.
+
+ @param Address Specifies the virtual address.
+ @param End The end address of the memory region.
+
+ @retval the index of the page upper directory table entry.
+ **/
+#define PUD_INDEX(Address) (((Address) >> PUD_SHIFT) & (ENTRYS_PER_PUD - 1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page middle directory table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page middle directory table entry.
+ **/
+#define PMD_INDEX(Address) (((Address) >> PMD_SHIFT) & (ENTRYS_PER_PMD - 1))
+/**
+ Get Specifies the virtual address corresponding to the index of the page table entry.
+
+ @param Address Specifies the virtual address.
+
+ @retval the index of the page table entry.
+ **/
+#define PTE_INDEX(Address) (((Address) >> EFI_PAGE_SHIFT) & (ENTRYS_PER_PTE - 1))
+
+/**
+ Calculates the value of the page table entry based on the specified virtual address and properties.
+
+ @param Address Specifies the virtual address.
+ @param Attributes Specifies the Attributes.
+
+ @retval the value of the page table entry.
+ **/
+#define MAKE_PTE(Address, Attributes) (PTE){((((Address) >> EFI_PAGE_SHIFT) << 12) | (Attributes))}
+/**
+ Calculates the value of the Huge page table entry based on the specified virtual address and properties.
+
+ @param Address Specifies the virtual address.
+ @param Attributes Specifies the Attributes.
+
+ @retval the value of the HUGE page table entry.
+ **/
+#define MAKE_HUGE_PTE(Address, Attributes) (((((Address) >> PMD_SHIFT) << PMD_SHIFT) | ((Attributes) | 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)
+#define HUGE_PAGE_SIZE (PMD_SIZE)
+
+ /**
+ Check that the global page directory table entry is empty.
+
+ @param pgd the global page directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pgd_none (
+ IN PGD pgd
+ )
+{
+ return (PGD_VAL(pgd) == (UINTN)PcdGet64(PcdInvalidPud));
+}
+
+ /**
+ Check that the page upper directory table entry is empty.
+
+ @param pud Page upper directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pud_none (
+ IN PUD pud
+ )
+{
+ return (PUD_VAL(pud) == (UINTN)PcdGet64 (PcdInvalidPmd));
+}
+
+ /**
+ Check that the page middle directory table entry is empty.
+
+ @param pmd Page middle directory struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pmd_none (
+ IN PMD pmd
+ )
+{
+ return (PMD_VAL(pmd) == (UINTN)PcdGet64(PcdInvalidPte));
+}
+ /**
+ Check that the page table entry is empty.
+
+ @param pmd Page table entry struct variables.
+
+ @retval 1 Is huge page table entry.
+ @retval 0 Isn't huge page table entry.
+ **/
+STATIC
+inline
+UINTN
+pte_none (
+ IN PTE pte
+ )
+{
+ return (!(PTE_VAL(pte) & (~PAGE_GLOBAL)));
+}
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
new file mode 100644
index 0000000000..d4eabdaed3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/pte.h
@@ -0,0 +1,57 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Tlb or TLB - Translation Lookaside Buffer
+ - HGLOBAL - Huge Global
+ - PFN - Page Frame number
+ - EXEC - Execute
+ - PLV - Privilege Level
+ - RPLV - Restricted Privilege Level
+ - SUC - Strong-ordered UnCached
+ - CC - Coherent Cached
+ - WUC - Weak-ordered UnCached
+**/
+#ifndef PTE_H_
+#define PTE_H_
+/*Page table property definitions */
+#define PAGE_VALID_SHIFT 0
+#define PAGE_DIRTY_SHIFT 1
+#define PAGE_PLV_SHIFT 2 /* 2~3, two bits */
+#define CACHE_SHIFT 4 /* 4~5, two bits */
+#define PAGE_GLOBAL_SHIFT 6
+#define PAGE_HUGE_SHIFT 6 /* HUGE is a PMD bit */
+
+#define PAGE_HGLOBAL_SHIFT 12 /* HGlobal is a PMD bit */
+#define PAGE_PFN_SHIFT 12
+#define PAGE_PFN_END_SHIFT 48
+#define PAGE_NO_READ_SHIFT 61
+#define PAGE_NO_EXEC_SHIFT 62
+#define PAGE_RPLV_SHIFT 63
+
+/* Used by TLB hardware (placed in EntryLo*) */
+#define PAGE_VALID ((UINTN)(1) << PAGE_VALID_SHIFT)
+#define PAGE_DIRTY ((UINTN)(1) << PAGE_DIRTY_SHIFT)
+#define PAGE_PLV ((UINTN)(3) << PAGE_PLV_SHIFT)
+#define PAGE_GLOBAL ((UINTN)(1) << PAGE_GLOBAL_SHIFT)
+#define PAGE_HUGE ((UINTN)(1) << PAGE_HUGE_SHIFT)
+#define PAGE_HGLOBAL ((UINTN)(1) << PAGE_HGLOBAL_SHIFT)
+#define PAGE_NO_READ ((UINTN)(1) << PAGE_NO_READ_SHIFT)
+#define PAGE_NO_EXEC ((UINTN)(1) << PAGE_NO_EXEC_SHIFT)
+#define PAGE_RPLV ((UINTN)(1) << PAGE_RPLV_SHIFT)
+#define CACHE_MASK ((UINTN)(3) << CACHE_SHIFT)
+#define PFN_SHIFT (EFI_PAGE_SHIFT - 12 + PAGE_PFN_SHIFT)
+
+#define PLV_KERNEL 0
+#define PLV_USER 3
+
+#define PAGE_USER (PLV_USER << PAGE_PLV_SHIFT)
+#define PAGE_KERNEL (PLV_KERN << PAGE_PLV_SHIFT)
+
+#define CACHE_SUC (0 << CACHE_SHIFT) /* Strong-ordered UnCached */
+#define CACHE_CC (1 << CACHE_SHIFT) /* Coherent Cached */
+#define CACHE_WUC (2 << CACHE_SHIFT) /* Weak-ordered UnCached */
+#endif
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (5 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase xianglai
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
This library provides a delay interface and a timing interface.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Include/Library/StableTimer.h | 42 +++
.../Library/StableTimerLib/Count.S | 26 ++
.../Library/StableTimerLib/TimerLib.c | 262 ++++++++++++++++++
.../Library/StableTimerLib/TimerLib.inf | 28 ++
4 files changed, 358 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h b/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
new file mode 100644
index 0000000000..bd6a1eb90f
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Include/Library/StableTimer.h
@@ -0,0 +1,42 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Csr - Cpu Status Register
+ - Calc - Calculation
+ - Freq - frequency
+**/
+
+#ifndef STABLE_TIMER_H_
+#define STABLE_TIMER_H_
+#include "Library/Cpu.h"
+
+/**
+ Gets the timer count value.
+
+ @param[] VOID
+
+ @retval timer count value.
+**/
+UINTN
+EFIAPI
+CsrReadTime (
+ VOID
+ );
+
+/**
+ Calculate the timer frequency.
+
+ @param[] VOID
+
+ @retval Timer frequency.
+**/
+UINT32
+EFIAPI
+CalcConstFreq (
+ VOID
+ );
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
new file mode 100644
index 0000000000..42f878caf8
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/Count.S
@@ -0,0 +1,26 @@
+#------------------------------------------------------------------------------
+#
+# Count for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#------------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+#include "LoongArchAsmMacro.h"
+#
+# Set cpu interrupts
+# @param A0 The interrupt number
+#
+ASM_FUNC(CpuSetIP)
+ csrrd T0, LOONGARCH_CSR_ECFG
+ or T0, T0, A0
+ csrwr T0, LOONGARCH_CSR_ECFG
+ jirl ZERO, RA,0
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
new file mode 100644
index 0000000000..21e3749ee6
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.c
@@ -0,0 +1,262 @@
+/** @file
+ Generic LoongArch implementation of TimerLib.h
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Freq - Frequency
+ - Csr - Cpu Status Register
+ - calc - calculate
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include "Library/StableTimer.h"
+#include "Library/Cpu.h"
+
+UINT32 StableTimerFreq = 0;
+
+/**
+ Gets the timer count value.
+
+ @param[] VOID
+
+ @retval timer count value.
+**/
+UINTN
+EFIAPI
+CsrReadTime (
+ VOID
+ )
+{
+ UINTN Value = 0;
+ __asm__ __volatile__(
+ " rdtime.d %0, $r0\n"
+ : "=r" (Value));
+ return Value;
+}
+
+/**
+ Calculate the timer frequency.
+
+ @param[] VOID
+
+ @retval Timer frequency.
+**/
+UINT32
+EFIAPI
+CalcConstFreq (
+ VOID
+ )
+{
+ UINT32 Result;
+ UINT32 BaseFreq;
+ UINT32 ClockMultiplier;
+ UINT32 ClockDivide;
+
+ LOONGARCH_GET_CPUCFG (BaseFreq, LOONGARCH_CPUCFG4);
+ LOONGARCH_GET_CPUCFG (Result, LOONGARCH_CPUCFG5);
+ ClockMultiplier = Result & 0xffff;
+ ClockDivide = (Result >> 16) & 0xffff;
+
+ if ((!BaseFreq)
+ || (!ClockMultiplier)
+ || (!ClockDivide))
+ {
+ return 0;
+ }
+ else {
+ return (BaseFreq * ClockMultiplier / ClockDivide);
+ }
+}
+/**
+ Get the timer frequency.
+
+ @param[] VOID
+
+ @retval Timer frequency.
+**/
+UINT32
+EFIAPI
+GetFreq (
+ VOID
+ )
+{
+ if (StableTimerFreq) {
+ } else {
+ StableTimerFreq = CalcConstFreq ();
+ }
+
+ return StableTimerFreq;
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ UINTN Count;
+ UINTN Ticks;
+ UINTN Start;
+ UINTN End;
+
+ Count = GetFreq ();
+ Count = (Count * MicroSeconds) / 1000000;
+ Start = CsrReadTime ();
+ End = Start + Count;
+
+ do {
+ Ticks = CsrReadTime ();
+ } 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 CsrReadTime ();
+}
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = BIT2;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = BIT48 - 1;
+ }
+
+ return GetFreq ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
new file mode 100644
index 0000000000..fef0fac08c
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
@@ -0,0 +1,28 @@
+## @file
+# Generic LoongArch implementation of TimerLib.h
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TimerLib
+ FILE_GUID = 740389C7-CC44-4A2F-88DC-89D97D312E7C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+
+[Sources.common]
+ TimerLib.c
+ Count.S
+
+[Packages]
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ IoLib
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (6 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver xianglai
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Platform PEI module for LoongArch platform initialization.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Loongson/LoongArchQemuPkg/Loongson.dec | 22 ++
.../Loongson/LoongArchQemuPkg/Loongson.dsc | 66 ++++-
.../Loongson/LoongArchQemuPkg/Loongson.fdf | 51 ++++
.../LoongArchQemuPkg/PlatformPei/Fv.c | 61 ++++
.../LoongArchQemuPkg/PlatformPei/MemDetect.c | 116 ++++++++
.../LoongArchQemuPkg/PlatformPei/Platform.c | 264 ++++++++++++++++++
.../LoongArchQemuPkg/PlatformPei/Platform.h | 87 ++++++
.../PlatformPei/PlatformPei.inf | 72 +++++
8 files changed, 738 insertions(+), 1 deletion(-)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
index 248b668fd1..aca53583f1 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -30,9 +30,31 @@
[PcdsFixedAtBuild, PcdsDynamic]
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000003
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000004
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|0x0|UINT64|0x00000008
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize|0x0|UINT32|0x00000009
gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize|0|UINT32|0x00000016
gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|0|UINT32|0x00000017
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase|0x0|UINT64|0x00000018
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreePadding|256|UINT32|0x00000019
+
gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase|0|UINT64|0x0000001c
gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize|0|UINT32|0x0000001d
+ gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop|0x0|UINT64|0x0000001e
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom|0x0|UINT64|0x00000022
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|0x0|UINT64|0x00000028
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize|0x0|UINT32|0x00000029
+
+[PcdsFixedAtBuild.LOONGARCH64]
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011
+
+[PcdsDynamic]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize|0x40000000|UINT64|0x00000041
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgSelectorAddress|0x0|UINT64|0x00000042
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFwCfgDataAddress|0x0|UINT64|0x00000043
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSwapPageDir|0x0|UINT64|0x00000044
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPgd|0x0|UINT64|0x00000045
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPud|0x0|UINT64|0x00000046
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd|0x0|UINT64|0x00000047
+ gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte|0x0|UINT64|0x00000048
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
index f23fed77e6..09b324c3f7 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -57,22 +57,58 @@
[LibraryClasses.common]
PcdLib | MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ TimerLib | Platform/Loongson/LoongArchQemuPkg/Library/StableTimerLib/TimerLib.inf
PrintLib | MdePkg/Library/BasePrintLib/BasePrintLib.inf
BaseMemoryLib | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
BaseLib | MdePkg/Library/BaseLib/BaseLib.inf
+ PerformanceLib | MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
PeCoffLib | MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ CacheMaintenanceLib | MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ UefiDecompressLib | MdePkg/Library/BaseUefiDecompressLib/BaseUefiDecompressLib.inf
PeCoffGetEntryPointLib | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
IoLib | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
SerialPortLib | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
DebugPrintErrorLevelLib | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ FdtLib | EmbeddedPkg/Library/FdtLib/FdtLib.inf
PeCoffExtraActionLib | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
DebugAgentLib | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
DebugLib | MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ PeiServicesLib | MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+[LibraryClasses.common.SEC]
+ ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+
+[LibraryClasses.common.PEI_CORE]
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ PeiServicesTablePointerLib | Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ MemoryAllocationLib | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ PeiCoreEntryPoint | MdePkg/Library/PeiCoreEntryPoint/PeiCoreEntryPoint.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ OemHookStatusCodeLib | MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+ PeCoffGetEntryPointLib | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ QemuFwCfgLib | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
+ MmuLib | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
+
+[LibraryClasses.common.PEIM]
+ HobLib | MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ PeiServicesTablePointerLib | Platform/Loongson/LoongArchQemuPkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ MemoryAllocationLib | MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+ PeimEntryPoint | MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ OemHookStatusCodeLib | MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+ PeCoffGetEntryPointLib | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ PeiResourcePublicationLib | MdePkg/Library/PeiResourcePublicationLib/PeiResourcePublicationLib.inf
+ ExtractGuidedSectionLib | MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+ PcdLib | MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+ QemuFwCfgS3Lib | OvmfPkg/Library/QemuFwCfgS3Lib/PeiQemuFwCfgS3LibFwCfg.inf
+ QemuFwCfgLib | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
+ MmuLib | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
################################################################################
@@ -119,11 +155,19 @@
# ASSERT_BREAKPOINT_ENABLED 0x10
# ASSERT_DEADLOOP_ENABLED 0x20
+#######################################################################################
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom | 0x90000000
gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress | 0x90000000
gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize | 0x10000
gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase | 0x90010000
gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize | 0x10000
-
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase | 0x1c400000
+ #
+ # minimal memory for uefi bios should be 512M
+ # 0x00000000 - 0x10000000
+ # 0x90000000 - 0xA0000000
+ #
+ gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop | 0xA0000000
[Components]
@@ -131,3 +175,23 @@
# SEC Phase modules
#
Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
+
+ #
+ # PEI Phase modules
+ #
+ MdeModulePkg/Core/Pei/PeiMain.inf
+ MdeModulePkg/Universal/PCD/Pei/Pcd.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ }
+ MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+ MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ }
+
+ Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+ }
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
index 128b3843db..f964304fdc 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -45,9 +45,60 @@ READ_LOCK_STATUS = TRUE
INF Platform/Loongson/LoongArchQemuPkg/Sec/SecMain.inf
+#####################################################################################################
+[FV.PEIFV]
+FvNameGuid = 6f856a84-de7d-4af9-93a3-342b4ecb46eb
+BlockSize = $(BLOCK_SIZE)
+FvAlignment = 16
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+
+APRIORI PEI {
+ INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+}
+
+#
+# PEI Phase modules
+#
+
+INF MdeModulePkg/Core/Pei/PeiMain.inf
+INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
+INF Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
+
#####################################################################################################
[Rule.Common.SEC]
FILE SEC = $(NAMED_GUID) {
TE TE Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
UI STRING ="$(MODULE_NAME)" Optional
}
+
+#####################################################################################################
+[Rule.Common.PEI_CORE]
+ FILE PEI_CORE = $(NAMED_GUID) {
+ TE TE Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING ="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
+[Rule.Common.PEIM]
+ FILE PEIM = $(NAMED_GUID) {
+ PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
new file mode 100644
index 0000000000..f79d4506b1
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Fv.c
@@ -0,0 +1,61 @@
+/** @file
+ Build FV related hobs for platform.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include "PiPei.h"
+#include "Platform.h"
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+
+/**
+ Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+ and DXE know about them.
+
+ @retval EFI_SUCCESS Platform PEI FVs were initialized successfully.
+
+**/
+EFI_STATUS
+PeiFvInitialization (
+ VOID
+ )
+{
+ DEBUG ((DEBUG_INFO, "Platform PEI Firmware Volume Initialization\n"));
+
+ //
+ // Create a memory allocation HOB for the PEI FV.
+ //
+ BuildMemoryAllocationHob (
+ PcdGet64 (PcdSecPeiTempRamBase),
+ PcdGet32 (PcdSecPeiTempRamSize),
+ EfiBootServicesData
+ );
+
+ //
+ // Let DXE know about the DXE FV
+ //
+ BuildFvHob (PcdGet64 (PcdFlashDxeFvBase), PcdGet32 (PcdFlashDxeFvSize));
+
+ //
+ // Let PEI know about the DXE FV so it can find the DXE Core
+ //
+ DEBUG ((DEBUG_INFO, "DXEFV base:%p size:%x\n", (VOID *) (UINTN)PcdGet64 (PcdFlashDxeFvBase),
+ PcdGet32 (PcdFlashDxeFvSize)));
+ PeiServicesInstallFvInfoPpi (
+ NULL,
+ (VOID *) (UINTN)PcdGet64 (PcdFlashDxeFvBase),
+ PcdGet32 (PcdFlashDxeFvSize),
+ NULL,
+ NULL
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
new file mode 100644
index 0000000000..c40d7d5c71
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/MemDetect.c
@@ -0,0 +1,116 @@
+/** @file
+ Memory Detection for Virtual Machines.
+
+ Copyright (c) 2021 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/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/ResourcePublicationLib.h>
+
+#include "Platform.h"
+
+/**
+ Publish PEI core memory
+
+ @return EFI_SUCCESS The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+PublishPeiMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Base;
+ UINT64 Size;
+ UINT64 RamTop;
+
+ //
+ // Determine the range of memory to use during PEI
+ //
+ Base = PcdGet64 (PcdSecPeiTempRamBase) + PcdGet32 (PcdSecPeiTempRamSize);
+ RamTop = PcdGet64 (PcdUefiRamTop);
+ Size = RamTop - Base;
+
+
+ //
+ // Publish this memory to the PEI Core
+ //
+ Status = PublishSystemMemory (Base, Size);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "Publish Memory Initialize done.\n"));
+ return Status;
+}
+
+/**
+ Peform Memory Detection
+ Publish system RAM and reserve memory regions
+**/
+VOID
+InitializeRamRegions (
+ VOID
+ )
+{
+ UINT64 Base;
+ UINT64 End;
+
+
+ //
+ // DDR memory space address range
+ // 0x00000000 - 0x10000000 lower 256M memory space
+ // 0x90000000 - BASE_4GB if there is
+ // BASE_4GB -
+ Base = PcdGet64 (PcdRamRegionsBottom);
+ End = Base + PcdGet64 (PcdRamSize) - 0x10000000;
+
+ //
+ // Create memory HOBs.
+ // Put memory below 4G address space at the first memory HOB
+ //
+ DEBUG ((DEBUG_INFO, "%a: MemoryBase=%llx, MemoryEnd=%llx\n", __FUNCTION__, Base, End));
+
+ if (End > BASE_4GB) {
+ AddMemoryRangeHob (Base, BASE_4GB);
+ AddMemoryRangeHob (BASE_4GB, End);
+ } else {
+
+ AddMemoryRangeHob (Base, End);
+ }
+ AddMemoryRangeHob (0x0, 0x10000000);
+
+ //
+ // Lock the scope of the cache.
+ //
+ BuildMemoryAllocationHob (
+ PcdGet64 (PcdSecPeiTempRamBase),
+ PcdGet32 (PcdSecPeiTempRamSize),
+ EfiACPIMemoryNVS
+ );
+
+ //
+ // SEC stores its table of GUIDed section handlers here.
+ //
+ BuildMemoryAllocationHob (
+ PcdGet64 (PcdGuidedExtractHandlerTableAddress),
+ PcdGet32 (PcdGuidedExtractHandlerTableSize),
+ EfiACPIMemoryNVS
+ );
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
new file mode 100644
index 0000000000..6f6c53fcab
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.c
@@ -0,0 +1,264 @@
+/** @file
+ Platform PEI driver
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Mem - Memory
+**/
+
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ResourcePublicationLib.h>
+#include <Guid/MemoryTypeInformation.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/MmuLib.h>
+#include <Guid/FdtHob.h>
+#include <libfdt.h>
+#include <Ppi/MasterBootMode.h>
+
+#include "Platform.h"
+
+/* TODO */
+EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
+ { EfiReservedMemoryType, 0x004 },
+ { EfiRuntimeServicesData, 0x024 },
+ { EfiRuntimeServicesCode, 0x030 },
+ { EfiBootServicesCode, 0x180 },
+ { EfiBootServicesData, 0xF00 },
+ { EfiMaxMemoryType, 0x000 }
+};
+
+//
+// Module globals
+//
+CONST EFI_PEI_PPI_DESCRIPTOR mPpiListBootMode = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMasterBootModePpiGuid,
+ NULL
+};
+
+/**
+ Create Reserved type memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddReservedMemoryBaseSizeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_MEMORY_RESERVED,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+/**
+ Create system type memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddMemoryBaseSizeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ UINT64 MemorySize
+ )
+{
+ BuildResourceDescriptorHob (
+ EFI_RESOURCE_SYSTEM_MEMORY,
+ EFI_RESOURCE_ATTRIBUTE_PRESENT |
+ EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
+ EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
+ EFI_RESOURCE_ATTRIBUTE_TESTED,
+ MemoryBase,
+ MemorySize
+ );
+}
+
+/**
+ Create memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddMemoryRangeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ EFI_PHYSICAL_ADDRESS MemoryLimit
+ )
+{
+ AddMemoryBaseSizeHob (MemoryBase, (UINT64) (MemoryLimit - MemoryBase));
+}
+/**
+ Create memory type information hand off block.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+MemMapInitialization (
+ VOID
+ )
+{
+ DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
+ //
+ // Create Memory Type Information HOB
+ //
+ BuildGuidDataHob (
+ &gEfiMemoryTypeInformationGuid,
+ mDefaultMemoryTypeInformation,
+ sizeof (mDefaultMemoryTypeInformation)
+ );
+}
+
+/**
+ Misc Initialization.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+MiscInitialization (
+ VOID
+ )
+{
+ DEBUG ((DEBUG_INFO, "==%a==\n", __func__));
+ //
+ // Creat CPU HOBs.
+ //
+ BuildCpuHob (PcdGet8 (PcdPrePiCpuMemorySize), PcdGet8 (PcdPrePiCpuIoSize));
+}
+/**
+ add fdt hand off block.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+AddFdtHob (VOID)
+{
+ VOID *Base;
+ VOID *NewBase;
+ UINTN FdtSize;
+ UINTN FdtPages;
+ UINT64 *FdtHobData;
+
+ Base = (VOID*)(UINTN)PcdGet64 (PcdDeviceTreeBase);
+ ASSERT (Base != NULL);
+
+ FdtSize = fdt_totalsize (Base) + PcdGet32 (PcdDeviceTreePadding);
+ FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
+ NewBase = AllocatePages (FdtPages);
+ ASSERT (NewBase != NULL);
+ fdt_open_into (Base, NewBase, EFI_PAGES_TO_SIZE (FdtPages));
+
+ FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof *FdtHobData);
+ ASSERT (FdtHobData != NULL);
+ *FdtHobData = (UINTN)NewBase;
+
+}
+
+/**
+ Fetch the size of system memory from QEMU.
+
+ @param VOID
+
+ @return VOID
+**/
+VOID
+SystemMemorySizeInitialization (
+ VOID
+ )
+{
+ UINT64 RamSize;
+ RETURN_STATUS PcdStatus;
+
+ QemuFwCfgSelectItem (QemuFwCfgItemRamSize);
+ RamSize= QemuFwCfgRead64 ();
+ DEBUG ((DEBUG_INFO, "%a: QEMU reports %dM system memory\n", __FUNCTION__,
+ RamSize/1024/1024));
+
+ //
+ // If the fw_cfg key or fw_cfg entirely is unavailable, no change to PCD.
+ //
+ if (RamSize == 0) {
+ return;
+ }
+
+ //
+ // Otherwise, set RamSize to PCD.
+ //
+ PcdStatus = PcdSet64S (PcdRamSize, RamSize);
+ ASSERT_RETURN_ERROR (PcdStatus);
+}
+
+/**
+ Perform Platform PEI initialization.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePlatform (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
+
+ Status = PeiServicesInstallPpi (&mPpiListBootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ SystemMemorySizeInitialization ();
+ PublishPeiMemory ();
+ PeiFvInitialization ();
+ InitializeRamRegions ();
+ MemMapInitialization ();
+ MiscInitialization ();
+ AddFdtHob ();
+ ConfigureMmu ();
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
new file mode 100644
index 0000000000..bc44f233e7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/Platform.h
@@ -0,0 +1,87 @@
+/** @file
+ Platform PEI module include file.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_H_
+#define PLATFORM_H_
+
+#include <IndustryStandard/Pci22.h>
+
+/**
+ Create system type memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddMemoryBaseSizeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ UINT64 MemorySize
+ );
+
+/**
+ Create memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddMemoryRangeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ EFI_PHYSICAL_ADDRESS MemoryLimit
+ );
+
+/**
+ Create Reserved type memory range hand off block.
+
+ @param MemoryBase memory base address.
+ @param MemoryLimit memory length.
+
+ @return VOID
+**/
+VOID
+AddReservedMemoryBaseSizeHob (
+ EFI_PHYSICAL_ADDRESS MemoryBase,
+ UINT64 MemorySize
+ );
+/**
+ Publish PEI core memory
+
+ @return EFI_SUCCESS The PEIM initialized successfully.
+
+**/
+EFI_STATUS
+PublishPeiMemory (
+ VOID
+ );
+/**
+ Publish system RAM and reserve memory regions
+
+**/
+VOID
+InitializeRamRegions (
+ VOID
+ );
+
+/**
+ Publish PEI & DXE (Decompressed) Memory based FVs to let PEI
+ and DXE know about them.
+
+ @retval EFI_SUCCESS Platform PEI FVs were initialized successfully.
+
+**/
+EFI_STATUS
+PeiFvInitialization (
+ VOID
+ );
+
+#endif // _PLATFORM_PEI_H_INCLUDED_
diff --git a/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
new file mode 100644
index 0000000000..e8d3ed0008
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
@@ -0,0 +1,72 @@
+
+## @file
+# Platform PEI driver
+#
+# Copyright (c) 2021 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
+
+[Sources]
+ Fv.c
+ MemDetect.c
+ Platform.c
+
+
+[Packages]
+ ArmVirtPkg/ArmVirtPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ OvmfPkg/OvmfPkg.dec
+
+[Ppis]
+ gEfiPeiMasterBootModePpiGuid
+
+[Guids]
+ gEfiMemoryTypeInformationGuid
+ gFdtHobGuid
+
+[LibraryClasses]
+ DebugLib
+ BaseMemoryLib
+ HobLib
+ IoLib
+ PeiResourcePublicationLib
+ PeiServicesLib
+ PeiServicesTablePointerLib
+ PeimEntryPoint
+ QemuFwCfgLib
+ PcdLib
+ TimerLib
+ MmuLib
+
+[Pcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreePadding
+
+[FixedPcd]
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamRegionsBottom
+ gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamBase
+ gLoongArchQemuPkgTokenSpaceGuid.PcdSecPeiTempRamSize
+ gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize
+ gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize
+
+[Depex]
+ TRUE
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (7 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
The driver produces EFI_CPU_ARCH_PROTOCOL,
Initialize the exception entry address.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c | 382 ++++++++++++++++++
.../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h | 153 +++++++
.../Drivers/CpuDxe/CpuDxe.inf | 56 +++
.../Drivers/CpuDxe/LoongArch64/Exception.c | 337 +++++++++++++++
.../Drivers/CpuDxe/LoongArch64/Fpu.S | 67 +++
.../Drivers/CpuDxe/LoongArch64/LoongArch.S | 288 +++++++++++++
6 files changed, 1283 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
new file mode 100644
index 0000000000..bff2bd0c0a
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c
@@ -0,0 +1,382 @@
+/** @file
+ CPU DXE Module to produce CPU ARCH Protocol
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Guid/IdleLoopEvent.h>
+#include <Uefi.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MmuLib.h>
+#include "CpuDxe.h"
+
+BOOLEAN mInterruptState = FALSE;
+
+/*
+ This function flushes the range of addresses from Start to Start+Length
+ from the processor's data cache. If Start is not aligned to a cache line
+ boundary, then the bytes before Start to the preceding cache line boundary
+ are also flushed. If Start+Length is not aligned to a cache line boundary,
+ then the bytes past Start+Length to the end of the next cache line boundary
+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
+ supported. If the data cache is fully coherent with all DMA operations, then
+ this function can just return EFI_SUCCESS. If the processor does not support
+ flushing a range of the data cache, then the entire data cache can be flushed.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param Start The beginning physical address to flush from the processor's data
+ cache.
+ @param Length The number of bytes to flush from the processor's data cache. This
+ function may flush more bytes than Length specifies depending upon
+ the granularity of the flush operation that the processor supports.
+ @param FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
+ the processor's data cache.
+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
+ by FlushType.
+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
+ from the processor's data cache.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+{
+
+ switch (FlushType) {
+ case EfiCpuFlushTypeWriteBack:
+ WriteBackDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeInvalidate:
+ InvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);
+ break;
+ case EfiCpuFlushTypeWriteBackInvalidate:
+ WriteBackInvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function enables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are enabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ EnableInterrupts ();
+
+ mInterruptState = TRUE;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function disables interrupt processing by the processor.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Interrupts are disabled on the processor.
+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ DisableInterrupts ();
+
+ mInterruptState = FALSE;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function retrieves the processor's current interrupt state a returns it in
+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts
+ are currently disabled, then FALSE is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param State A pointer to the processor's current interrupt state. Set to TRUE if
+ interrupts are enabled and FALSE if interrupts are disabled.
+
+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = mInterruptState;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function generates an INIT on the processor. If this function succeeds, then the
+ processor will be reset, and control will not be returned to the caller. If InitType is
+ not supported by this processor, or the processor cannot programmatically generate an
+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param InitType The type of processor INIT to perform.
+
+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
+ by this processor.
+ @retval EFI_DEVICE_ERROR The processor INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+
+ @param InterruptType Interrupt Type.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+
+ return RegisterInterruptHandler (InterruptType, InterruptHandler);
+}
+
+/**
+ Returns a timer value from one of the CPU's internal timers. There is no
+ inherent time interval between ticks but is a function of the CPU frequency.
+
+ @param This - Protocol instance structure.
+ @param TimerIndex - Specifies which CPU timer is requested.
+ @param TimerValue - Pointer to the returned timer value.
+ @param TimerPeriod - A pointer to the amount of time that passes
+ in femtoseconds (10-15) for each increment
+ of TimerValue. If TimerValue does not
+ increment at a predictable rate, then 0 is
+ returned. The amount of time that has
+ passed between two calls to GetTimerValue()
+ can be calculated with the formula
+ (TimerValue2 - TimerValue1) * TimerPeriod.
+ This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS - If the CPU timer count was returned.
+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.
+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.
+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+/**
+ This function modifies the attributes for the memory region specified by BaseAddress and
+ Length from their current attributes to the attributes specified by Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
+ resource range specified by BaseAddress and Length.
+ The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 EfiAttributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN LoongArchAttributes;
+ UINTN RegionBaseAddress;
+ UINTN RegionLength;
+ UINTN RegionLoongArchAttributes;
+
+ if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
+ // Minimum granularity is SIZE_4KB (4KB on ARM)
+ DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",
+ BaseAddress,
+ Length,
+ EfiAttributes));
+
+ return EFI_UNSUPPORTED;
+ }
+ // Convert the 'Attribute' into LoongArch Attribute
+ LoongArchAttributes = EfiAttributeToLoongArchAttribute (EfiAttributes);
+
+ // Get the region starting from 'BaseAddress' and its 'Attribute'
+ RegionBaseAddress = BaseAddress;
+ Status = GetLoongArchMemoryRegion (RegionBaseAddress, BaseAddress + Length,
+ &RegionLength, &RegionLoongArchAttributes);
+
+ LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
+ // Data & Instruction Caches are flushed when we set new memory attributes.
+ // So, we only set the attributes if the new region is different.
+ if (EFI_ERROR (Status) || (RegionLoongArchAttributes != LoongArchAttributes) ||
+ ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
+ {
+ return LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function for idle events.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+ @param VOID
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CpuSleep ();
+}
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE CpuHandle = NULL;
+EFI_CPU_ARCH_PROTOCOL Cpu = {
+ CpuFlushCpuDataCache,
+ CpuEnableInterrupt,
+ CpuDisableInterrupt,
+ CpuGetInterruptState,
+ CpuInit,
+ CpuRegisterInterruptHandler,
+ CpuGetTimerValue,
+ CpuSetMemoryAttributes,
+ 0, // NumberOfTimers
+ 4, // DmaBufferAlignment
+};
+
+
+/**
+ Initialize the state information for the CPU Architectural Protocol.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to the System Table.
+
+ @retval EFI_SUCCESS Thread can be successfully created
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ @retval EFI_DEVICE_ERROR Cannot create the thread
+**/
+EFI_STATUS
+CpuDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT IdleLoopEvent;
+
+ InitializeExceptions (&Cpu);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &CpuHandle,
+ &gEfiCpuArchProtocolGuid, &Cpu,
+ NULL
+ );
+
+ //
+ // Setup a callback for idle events
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ IdleLoopEventCallback,
+ NULL,
+ &gIdleLoopEventGuid,
+ &IdleLoopEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
new file mode 100644
index 0000000000..062f366ba2
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h
@@ -0,0 +1,153 @@
+/** @file
+ CPU DXE Module to produce CPU ARCH Protocol and CPU MP Protocol
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Protocol/Cpu.h>
+
+/**
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by 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 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
+RegisterDebuggerInterruptHandler (
+ 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
+ );
+
+/** Exception module initialization
+ This function sets the exception base address.
+
+ @param Cpu A pointer to the CPU architecture protocol structure.
+
+ @retval EFI_SUCCESS Initialization succeeded
+ @retval EFI_NOT_FOUND Could not Found resources.
+ @retval EFI_OUT_OF_RESOURCES No enough resources.
+**/
+EFI_STATUS
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ );
+
+/** Common exception entry
+ Exception handling is the entry point for the C environment,
+ This function does different things depending on the exception type.
+
+ @param SystemContext The system context at the time of the exception.
+
+ @retval VOID.
+**/
+VOID
+EFIAPI
+CommonExceptionEntry (
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+extern CHAR8 LoongArchException[], LoongArchExceptionEnd[];
+/** Set Exception Base Address
+
+ @param addr Exception Base Address.
+
+ @retval The Old Exception Base Address.
+**/
+extern
+UINT64
+SetEbase (
+ EFI_PHYSICAL_ADDRESS addr
+ );
+/*
+ Load the FPU with signalling NANS. This bit pattern we're using has
+ the property that no matter whether considered as single or as double
+ precision represents signaling NANS.
+
+ @param fcsr The value to initialize FCSR0
+
+ @retval The Old Exception Base Address.
+ */
+extern
+VOID
+InitFpu (
+ UINT32 fcsr
+ );
+
+#endif // __CPU_DXE_H__
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
new file mode 100644
index 0000000000..a5e93efdeb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# CPU driver installs CPU Architecture Protocol and CPU MP protocol.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuDxe
+ FILE_GUID = bf954921-25c1-48c0-9bfb-8d0cd7ee92da
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = CpuDxeInitialize
+
+[Sources.Common]
+ CpuDxe.c
+ CpuDxe.h
+
+[Sources.LOONGARCH64]
+ LoongArch64/Exception.c
+ LoongArch64/LoongArch.S
+ LoongArch64/Fpu.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ CpuLib
+ DebugLib
+ DxeServicesTableLib
+ HobLib
+ PeCoffGetEntryPointLib
+ UefiDriverEntryPoint
+ UefiLib
+ MmuLib
+
+[Protocols]
+ gEfiCpuArchProtocolGuid
+ gEfiMpServiceProtocolGuid
+
+[Guids]
+ gEfiDebugImageInfoTableGuid
+ gIdleLoopEventGuid
+
+[Depex]
+ TRUE
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
new file mode 100644
index 0000000000..42cd91feb7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c
@@ -0,0 +1,337 @@
+/** @file
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - ESTAT - Exception Status
+ - ECFG - Exception Configure
+ - ERA - Exception Return Address
+ - BADV - Bad Virtual Address
+ - BADI - Bad Instructions
+ - Epc or EPC or epc - Exception Program Counter
+ - pc or PC or pc - Program Counter
+ - CRMD - Current Mode
+ - PRMD - Previous Mode
+ - CsrEuen - Cpu Status Register Extern Unit Enable
+ - fpu or fp or FP - Float Point Unit
+ - LOONGARCH - Loongson Arch
+ - Irq - Interrupt ReQuest
+**/
+
+#include <string.h>
+#include "Library/Cpu.h"
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include "CpuDxe.h"
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/DebugImageInfoTable.h>
+
+
+
+EFI_EXCEPTION_CALLBACK gExceptionHandlers[MAX_LOONGARCH_EXCEPTION + 1];
+EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_LOONGARCH_EXCEPTION + 1];
+
+/**
+ 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
+ )
+{
+ if (InterruptType > MAX_LOONGARCH_EXCEPTION) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((InterruptHandler != NULL)
+ && (gExceptionHandlers[InterruptType] != NULL))
+ {
+ return EFI_ALREADY_STARTED;
+ }
+
+ gExceptionHandlers[InterruptType] = InterruptHandler;
+
+ return EFI_SUCCESS;
+}
+/**
+ This function calls the corresponding exception handler based on the exception type.
+
+ @param ExceptionType Exception Type.
+ @param SystemContext The system context at the time of the exception.
+
+ @retval VOID
+**/
+STATIC VOID
+EFIAPI
+InterruptHandler (
+ IN INT32 ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ INT32 Pending;
+ /*irq [13-0] NMI IPI TI PCOV hw IP10-IP2 soft IP1-IP0*/
+ Pending = ((SystemContext.SystemContextLoongArch64->ESTAT) &
+ (SystemContext.SystemContextLoongArch64->ECFG) & 0x1fff);
+ if (Pending & (1 << 11/*TI*/)) {
+ gExceptionHandlers[ExceptionType] (ExceptionType, SystemContext);
+ } else {
+ DEBUG ((DEBUG_INFO, "Pending: 0x%0x, ExceptionType: 0x%0x\n", Pending, ExceptionType));
+ }
+}
+
+/**
+ Use the EFI Debug Image Table to lookup the FaultAddress and find which PE/COFF image
+ it came from. As long as the PE/COFF image contains a debug directory entry a
+ string can be returned. For ELF and Mach-O images the string points to the Mach-O or ELF
+ image. Microsoft tools contain a pointer to the PDB file that contains the debug information.
+
+ @param FaultAddress Address to find PE/COFF image for.
+ @param ImageBase Return load address of found image
+ @param PeCoffSizeOfHeaders Return the size of the PE/COFF header for the image that was found
+
+ @retval NULL FaultAddress not in a loaded PE/COFF image.
+ @retval Path and file name of PE/COFF image.
+
+**/
+CHAR8 *
+GetImageName (
+ IN UINTN FaultAddress,
+ OUT UINTN *ImageBase,
+ OUT UINTN *PeCoffSizeOfHeaders
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugTableHeader;
+ EFI_DEBUG_IMAGE_INFO *DebugTable;
+ UINTN Entry;
+ CHAR8 *Address;
+
+ Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugTableHeader);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ DebugTable = DebugTableHeader->EfiDebugImageInfoTable;
+ if (DebugTable == NULL) {
+ return NULL;
+ }
+
+ Address = (CHAR8 *)(UINTN)FaultAddress;
+ for (Entry = 0; Entry < DebugTableHeader->TableSize; Entry++, DebugTable++) {
+ if (DebugTable->NormalImage != NULL) {
+ if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&
+ (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
+ if ((Address >= (CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) &&
+ (Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) {
+ *ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;
+ *PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase);
+ return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ pass a file name string that contains the path, return file name.
+
+ @param FullName Path and file name
+
+ @retval file name.
+**/
+STATIC
+CONST CHAR8 *
+BaseName (
+ IN CONST CHAR8 *FullName
+ )
+{
+ CONST CHAR8 *Str;
+
+ Str = FullName + AsciiStrLen (FullName);
+
+ while (--Str > FullName) {
+ if (*Str == '/' || *Str == '\\') {
+ return Str + 1;
+ }
+ }
+ return Str;
+}
+
+/** Default Exception Handler Function
+ This function is called when an exception occurs that cannot be handled,
+ and this function prints the system context information when the interrupt occurred
+
+ @param SystemContext The system context at the time of the exception.
+
+ @retval VOID.
+**/
+STATIC
+VOID
+EFIAPI
+DefaultHandler (
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR8 *ImageName;
+ UINTN ImageBase, Epc;
+ UINTN PeCoffSizeOfHeader;
+
+ DEBUG ((DEBUG_ERROR, "CRMD 0x%llx\n", SystemContext.SystemContextLoongArch64->CRMD));
+ DEBUG ((DEBUG_ERROR, "PRMD 0x%llx\n", SystemContext.SystemContextLoongArch64->PRMD));
+ DEBUG ((DEBUG_ERROR, "ECFG 0x%llx\n", SystemContext.SystemContextLoongArch64->ECFG));
+ DEBUG ((DEBUG_ERROR, "ESTAT 0x%llx\n", SystemContext.SystemContextLoongArch64->ESTAT));
+ DEBUG ((DEBUG_ERROR, "ERA 0x%llx\n", SystemContext.SystemContextLoongArch64->ERA));
+ DEBUG ((DEBUG_ERROR, "BADV 0x%llx\n", SystemContext.SystemContextLoongArch64->BADV));
+ DEBUG ((DEBUG_ERROR, "BADI 0x%llx\n", SystemContext.SystemContextLoongArch64->BADI));
+
+ Epc = SystemContext.SystemContextLoongArch64->ERA;
+ ImageName = GetImageName (Epc, &ImageBase, &PeCoffSizeOfHeader);
+ if (ImageName != NULL) {
+ DEBUG ((DEBUG_ERROR, "PC 0x%012lx (0x%012lx+0x%08x) [ 0] %a\n",
+ Epc, ImageBase,
+ Epc - ImageBase, BaseName (ImageName)));
+ } else {
+ DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Epc));
+ }
+
+ while (1);
+}
+
+/** Common exception entry
+ Exception handling is the entry point for the C environment,
+ This function does different things depending on the exception type.
+
+ @param SystemContext The system context at the time of the exception.
+
+ @retval VOID.
+**/
+VOID
+EFIAPI
+CommonExceptionEntry (
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ INT32 ExceptionType;
+ UINT64 CsrEuen, FpuStatus;
+
+ ExceptionType = SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC;
+ ExceptionType = ExceptionType >> CSR_ESTAT_EXC_SHIFT;
+
+ LOONGARCH_CSR_READQ (CsrEuen, LOONGARCH_CSR_EUEN);
+ FpuStatus = CsrEuen & CSR_EUEN_FPEN;
+ switch (ExceptionType) {
+ case EXC_INT:
+ /*
+ * handle interrupt exception
+ */
+ InterruptHandler (ExceptionType, SystemContext);
+ if (!FpuStatus) {
+ LOONGARCH_CSR_READQ (CsrEuen, LOONGARCH_CSR_EUEN);
+ if (CsrEuen & CSR_EUEN_FPEN) {
+ /*
+ * Since Hw FP is enabled during interrupt handler,
+ * disable FP
+ */
+ CsrEuen &= ~CSR_EUEN_FPEN;
+ LOONGARCH_CSR_WRITEQ (CsrEuen, LOONGARCH_CSR_EUEN);
+ }
+ }
+ break;
+ case EXC_FPDIS:
+ /*
+ * Hardware FP disabled exception,
+ * Enable and init FP registers here
+ */
+ LOONGARCH_ENABLR_FPU ();
+ InitFpu(FPU_CSR_RN);
+ break;
+ default:
+ DefaultHandler(SystemContext);
+ break;
+ }
+}
+
+/** Exception module initialization
+ This function sets the exception base address.
+
+ @param Cpu A pointer to the CPU architecture protocol structure.
+
+ @retval EFI_SUCCESS Initialization succeeded
+ @retval EFI_NOT_FOUND Could not Found resources.
+ @retval EFI_OUT_OF_RESOURCES No enough resources.
+**/
+EFI_STATUS
+InitializeExceptions (
+ IN EFI_CPU_ARCH_PROTOCOL *Cpu
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IrqEnabled;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ ZeroMem (gExceptionHandlers, sizeof (*gExceptionHandlers));
+
+ //
+ // Disable interrupts
+ //
+ Cpu->GetInterruptState (Cpu, &IrqEnabled);
+ Cpu->DisableInterrupt (Cpu);
+
+ //
+ // EFI does not use the FIQ, but a debugger might so we must disable
+ // as we take over the exception vectors.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ 1,
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Set Exception Base Address\n"));
+ CopyMem ((char *)Address, LoongArchException, (LoongArchExceptionEnd - LoongArchException));
+ InvalidateInstructionCacheRange ((char *)Address, (LoongArchExceptionEnd - LoongArchException));
+
+ SetEbase (Address);
+ DEBUG ((DEBUG_INFO, "LoongArchException address: 0x%p\n", Address));
+ DEBUG ((DEBUG_INFO, "LoongArchExceptionEnd address: 0x%p\n", Address + (LoongArchExceptionEnd - LoongArchException)));
+
+ DEBUG ((DEBUG_INFO, "InitializeExceptions, IrqEnabled = %x\n", IrqEnabled));
+ if (IrqEnabled) {
+ //
+ // Restore interrupt state
+ //
+ Status = Cpu->EnableInterrupt (Cpu);
+ }
+
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
new file mode 100644
index 0000000000..f6cab5c9e7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S
@@ -0,0 +1,67 @@
+#------------------------------------------------------------------------------
+#
+# Fpu for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Glossary:
+# - CsrEuen - Cpu Status Register Extern Unit Enable
+# - FPEN - FPU Enable
+# - fpu or fp or FP - Float Point Unit
+#-----------------------------------------------------------------------------
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+#include "Library/Cpu.h"
+#include "CpuDxe.h"
+#include "LoongArchAsmMacro.h"
+
+/*
+ Load the FPU with signalling NANS. This bit pattern we're using has
+ the property that no matter whether considered as single or as double
+ precision represents signaling NANS.
+
+ The value to initialize FCSR0 to comes in $A0.
+ */
+ASM_FUNC(InitFpu)
+ li.d T1, CSR_EUEN_FPEN
+ csrxchg T1, T1, LOONGARCH_CSR_EUEN
+
+ movgr2fcsr FCSR0, A0
+ li.d T1, -1 # SNaN
+ movgr2fr.d $f0, T1
+ movgr2fr.d $f1, T1
+ movgr2fr.d $f2, T1
+ movgr2fr.d $f3, T1
+ movgr2fr.d $f4, T1
+ movgr2fr.d $f5, T1
+ movgr2fr.d $f6, T1
+ movgr2fr.d $f7, T1
+ movgr2fr.d $f8, T1
+ movgr2fr.d $f9, T1
+ movgr2fr.d $f10, T1
+ movgr2fr.d $f11, T1
+ movgr2fr.d $f12, T1
+ movgr2fr.d $f13, T1
+ movgr2fr.d $f14, T1
+ movgr2fr.d $f15, T1
+ movgr2fr.d $f16, T1
+ movgr2fr.d $f17, T1
+ movgr2fr.d $f18, T1
+ movgr2fr.d $f19, T1
+ movgr2fr.d $f20, T1
+ movgr2fr.d $f21, T1
+ movgr2fr.d $f22, T1
+ movgr2fr.d $f23, T1
+ movgr2fr.d $f24, T1
+ movgr2fr.d $f25, T1
+ movgr2fr.d $f26, T1
+ movgr2fr.d $f27, T1
+ movgr2fr.d $f28, T1
+ movgr2fr.d $f29, T1
+ movgr2fr.d $f30, T1
+ movgr2fr.d $f31, T1
+
+ jirl ZERO, RA, 0
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
new file mode 100644
index 0000000000..09adef4610
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S
@@ -0,0 +1,288 @@
+#------------------------------------------------------------------------------
+#
+# LoongArch for LoongArch
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Glossary:
+# - CsrEuen - Cpu Status Register Extern Unit Enable
+# - fpu - Float Point Unit
+# - LOONGARCH - Loongson Arch
+# - Ebase - Exception Base Address
+#-----------------------------------------------------------------------------
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__
+#endif
+
+#include "Library/Cpu.h"
+#include "CpuDxe.h"
+#include "LoongArchAsmMacro.h"
+
+#define RSIZE 8 /* 64 bit mode register size */
+#define RLOGSIZE 3
+
+
+/*
+ Main exception handler. Not really a leaf routine but not a normal
+ function either. Save away the entire cpu state end enter exception mode.
+ */
+ASM_FUNC(Exception_handler)
+
+ csrrd SP, LOONGARCH_CSR_KS1
+
+ addi.d T0, $r0, -0x10
+ and SP, SP, T0
+ addi.d SP, SP, -((CSR_NUM + BASE_NUM + FP_BASE_NUM) * RSIZE)
+
+ st.d RA, SP, RA_NUM * RSIZE
+ st.d GP, SP, GP_NUM * RSIZE
+ st.d A0, SP, A0_NUM * RSIZE
+ st.d A1, SP, A1_NUM * RSIZE
+ st.d A2, SP, A2_NUM * RSIZE
+ st.d A3, SP, A3_NUM * RSIZE
+ st.d A4, SP, A4_NUM * RSIZE
+ st.d A5, SP, A5_NUM * RSIZE
+ st.d A6, SP, A6_NUM * RSIZE
+ st.d A7, SP, A7_NUM * RSIZE
+ st.d T1, SP, T1_NUM * RSIZE
+ st.d T2, SP, T2_NUM * RSIZE
+ st.d T3, SP, T3_NUM * RSIZE
+ st.d T4, SP, T4_NUM * RSIZE
+ st.d T5, SP, T5_NUM * RSIZE
+ st.d T6, SP, T6_NUM * RSIZE
+ st.d T7, SP, T7_NUM * RSIZE
+ st.d T8, SP, T8_NUM * RSIZE
+ st.d TP, SP, TP_NUM * RSIZE
+ st.d FP, SP, FP_NUM * RSIZE
+ st.d S0, SP, S0_NUM * RSIZE
+ st.d S1, SP, S1_NUM * RSIZE
+ st.d S2, SP, S2_NUM * RSIZE
+ st.d S3, SP, S3_NUM * RSIZE
+ st.d S4, SP, S4_NUM * RSIZE
+ st.d S5, SP, S5_NUM * RSIZE
+ st.d S6, SP, S6_NUM * RSIZE
+ st.d S7, SP, S7_NUM * RSIZE
+ st.d S8, SP, S8_NUM * RSIZE
+
+ /*
+ * save T0/SP from scratch registers on stack
+ */
+ csrrd T0, LOONGARCH_CSR_KS0
+ st.d T0, SP, T0_NUM * RSIZE
+ csrrd T0, LOONGARCH_CSR_KS1
+ st.d T0, SP, SP_NUM * RSIZE
+
+ csrrd T0, LOONGARCH_CSR_CRMD
+ st.d T0, SP, (LOONGARCH_CSR_CRMD + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_PRMD
+ st.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_ECFG
+ st.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_ESTAT
+ st.d T0, SP, (LOONGARCH_CSR_ESTAT + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_EPC
+ st.d T0, SP, (LOONGARCH_CSR_EPC+ BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_BADV
+ st.d T0, SP, (LOONGARCH_CSR_BADV + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_BADI
+ st.d T0, SP, (LOONGARCH_CSR_BADI + BASE_NUM) * RSIZE
+ csrrd T0, LOONGARCH_CSR_EUEN
+ st.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE
+
+ /* Save FPU context */
+ ori T1, ZERO, CSR_EUEN_FPEN
+ and T2, T0, T1
+ beqz T2, 1f
+
+ fst.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE
+ fst.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE
+
+ movfcsr2gr T3, FCSR0
+ st.d T3, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE
+ movcf2gr T3, $fcc0
+ or T2, T3, ZERO
+ movcf2gr T3, $fcc1
+ bstrins.d T2, T3, 0xf, 0x8
+ movcf2gr T3, $fcc2
+ bstrins.d T2, T3, 0x17, 0x10
+ movcf2gr T3, $fcc3
+ bstrins.d T2, T3, 0x1f, 0x18
+ movcf2gr T3, $fcc4
+ bstrins.d T2, T3, 0x27, 0x20
+ movcf2gr T3, $fcc5
+ bstrins.d T2, T3, 0x2f, 0x28
+ movcf2gr T3, $fcc6
+ bstrins.d T2, T3, 0x37, 0x30
+ movcf2gr T3, $fcc7
+ bstrins.d T2, T3, 0x3f, 0x38
+ st.d T2, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE
+1:
+ or A0, SP, ZERO
+ bl CommonExceptionEntry
+ /*disable interrupt*/
+ li.d T0, (1 << 2)
+ csrxchg ZERO, T0, LOONGARCH_CSR_CRMD
+
+ ld.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE
+ csrwr T0, LOONGARCH_CSR_PRMD
+ ld.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE
+ csrwr T0, LOONGARCH_CSR_ECFG
+ ld.d T0, SP, (LOONGARCH_CSR_EPC + BASE_NUM) * RSIZE
+ csrwr T0, LOONGARCH_CSR_EPC
+
+ ld.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE
+ ori T1, ZERO, CSR_EUEN_FPEN
+ and T2, T0, T1
+ beqz T2, 2f
+
+ /*
+ * check previous FP state
+ * restore FP contect if FP enabled
+ */
+ fld.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE
+ fld.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE
+
+ ld.d T0, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE
+ movgr2fcsr FCSR0, T0
+ ld.d T0, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE
+ bstrpick.d T1, T0, 7, 0
+ movgr2cf $fcc0, T1
+ bstrpick.d T1, T0, 15, 8
+ movgr2cf $fcc1, T1
+ bstrpick.d T1, T0, 23, 16
+ movgr2cf $fcc2, T1
+ bstrpick.d T1, T0, 31, 24
+ movgr2cf $fcc3, T1
+ bstrpick.d T1, T0, 39, 32
+ movgr2cf $fcc4, T1
+ bstrpick.d T1, T0, 47, 40
+ movgr2cf $fcc5, T1
+ bstrpick.d T1, T0, 55, 48
+ movgr2cf $fcc6, T1
+ bstrpick.d T1, T0, 63, 56
+ movgr2cf $fcc7, T1
+2:
+ ld.d RA, SP, RA_NUM * RSIZE
+ ld.d GP, SP, GP_NUM * RSIZE
+ ld.d A0, SP, A0_NUM * RSIZE
+ ld.d A1, SP, A1_NUM * RSIZE
+ ld.d A2, SP, A2_NUM * RSIZE
+ ld.d A3, SP, A3_NUM * RSIZE
+ ld.d A4, SP, A4_NUM * RSIZE
+ ld.d A5, SP, A5_NUM * RSIZE
+ ld.d A6, SP, A6_NUM * RSIZE
+ ld.d A7, SP, A7_NUM * RSIZE
+ ld.d T0, SP, T0_NUM * RSIZE
+ ld.d T1, SP, T1_NUM * RSIZE
+ ld.d T2, SP, T2_NUM * RSIZE
+ ld.d T3, SP, T3_NUM * RSIZE
+ ld.d T4, SP, T4_NUM * RSIZE
+ ld.d T5, SP, T5_NUM * RSIZE
+ ld.d T6, SP, T6_NUM * RSIZE
+ ld.d T7, SP, T7_NUM * RSIZE
+ ld.d T8, SP, T8_NUM * RSIZE
+ ld.d TP, SP, TP_NUM * RSIZE
+ ld.d FP, SP, FP_NUM * RSIZE
+ ld.d S0, SP, S0_NUM * RSIZE
+ ld.d S1, SP, S1_NUM * RSIZE
+ ld.d S2, SP, S2_NUM * RSIZE
+ ld.d S3, SP, S3_NUM * RSIZE
+ ld.d S4, SP, S4_NUM * RSIZE
+ ld.d S5, SP, S5_NUM * RSIZE
+ ld.d S6, SP, S6_NUM * RSIZE
+ ld.d S7, SP, S7_NUM * RSIZE
+ ld.d S8, SP, S8_NUM * RSIZE
+
+ ld.d SP, SP, SP_NUM * RSIZE
+ ertn
+
+/*
+ Exception trampoline copied down to RAM after initialization.
+ */
+ASM_FUNC(LoongArchException)
+ csrwr T0, LOONGARCH_CSR_KS0
+ csrwr SP, LOONGARCH_CSR_KS1
+ la T0, Exception_handler
+ jirl ZERO, T0, 0
+.globl LoongArchExceptionEnd
+LoongArchExceptionEnd:
+
+/*
+ Set Exception Base Address.
+ */
+ASM_FUNC(SetEbase)
+ /*
+ * clear Vint cofigure
+ * all exceptions share the same interrupt entry
+ */
+ csrrd T0, LOONGARCH_CSR_ECFG
+ li.d T1, ~0x70000
+ and T0, T0, T1
+ csrwr T0, LOONGARCH_CSR_ECFG
+
+ /*set ebase*/
+ csrwr A0, LOONGARCH_CSR_EBASE
+ jirl ZERO, RA, 0
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (8 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver xianglai
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Add PCI CpuIo protocol.there is no fix translation
offset between I/O port accesses and MMIO accesses.
Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL
to add the translation for IO access.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c | 548 ++++++++++++++++++
.../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h | 219 +++++++
.../Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf | 40 ++
3 files changed, 807 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
new file mode 100644
index 0000000000..f5154eea7a
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c
@@ -0,0 +1,548 @@
+/** @file
+ Produces the CPU I/O 2 Protocol.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/CpuIo2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "PciCpuIo2Dxe.h"
+
+//
+// Handle for the CPU I/O 2 Protocol
+//
+STATIC EFI_HANDLE mHandle = NULL;
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mInStride[] = {
+ 1, // EfiCpuIoWidthUint8
+ 2, // EfiCpuIoWidthUint16
+ 4, // EfiCpuIoWidthUint32
+ 8, // EfiCpuIoWidthUint64
+ 0, // EfiCpuIoWidthFifoUint8
+ 0, // EfiCpuIoWidthFifoUint16
+ 0, // EfiCpuIoWidthFifoUint32
+ 0, // EfiCpuIoWidthFifoUint64
+ 1, // EfiCpuIoWidthFillUint8
+ 2, // EfiCpuIoWidthFillUint16
+ 4, // EfiCpuIoWidthFillUint32
+ 8 // EfiCpuIoWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+STATIC CONST UINT8 mOutStride[] = {
+ 1, // EfiCpuIoWidthUint8
+ 2, // EfiCpuIoWidthUint16
+ 4, // EfiCpuIoWidthUint32
+ 8, // EfiCpuIoWidthUint64
+ 1, // EfiCpuIoWidthFifoUint8
+ 2, // EfiCpuIoWidthFifoUint16
+ 4, // EfiCpuIoWidthFifoUint32
+ 8, // EfiCpuIoWidthFifoUint64
+ 0, // EfiCpuIoWidthFillUint8
+ 0, // EfiCpuIoWidthFillUint16
+ 0, // EfiCpuIoWidthFillUint32
+ 0 // EfiCpuIoWidthFillUint64
+};
+
+/**
+ Check parameters to a CPU I/O 2 Protocol service request.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The parameters for this request pass the checks.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+CpuIoCheckParameter (
+ IN BOOLEAN MmioOperation,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT64 MaxCount;
+ UINT64 Limit;
+
+ //
+ // Check to see if Buffer is NULL
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Width is in the valid range
+ //
+ if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For FIFO type, the target address won't increase during the access,
+ // so treat Count as 1
+ //
+ if ((Width >= EfiCpuIoWidthFifoUint8)
+ && (Width <= EfiCpuIoWidthFifoUint64))
+ {
+ Count = 1;
+ }
+
+ //
+ // Check to see if Width is in the valid range for I/O Port operations
+ //
+ Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ if ((!MmioOperation)
+ && (Width == EfiCpuIoWidthUint64))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Address is aligned
+ //
+ if ((Address & (UINT64) (mInStride[Width] - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check to see if any address associated with this transfer exceeds the maximum
+ // allowed address. The maximum address implied by the parameters passed in is
+ // Address + Size * Count. If the following condition is met, then the transfer
+ // is not supported.
+ //
+ // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
+ //
+ // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
+ // can also be the maximum integer value supported by the CPU, this range
+ // check must be adjusted to avoid all overflow conditions.
+ //
+ // The following form of the range check is equivalent but assumes that
+ // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
+ //
+ Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
+ if (Count == 0) {
+ if (Address > Limit) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ MaxCount = RShiftU64 (Limit, Width);
+ if (MaxCount < (Count - 1)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Check to see if Buffer is aligned
+ //
+ if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+ Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ *Uint8Buffer = MmioRead8 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint64) {
+ *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint64) {
+ MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Address += PcdGet64 (PcdPciIoTranslation);
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ *Uint8Buffer = MmioRead8 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ //
+ // Make sure the parameters are valid
+ //
+ Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Address += PcdGet64 (PcdPciIoTranslation);
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// CPU I/O 2 Protocol instance
+//
+STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = {
+ {
+ CpuMemoryServiceRead,
+ CpuMemoryServiceWrite
+ },
+ {
+ CpuIoServiceRead,
+ CpuIoServiceWrite
+ }
+};
+
+
+/**
+ The user Entry Point for module CpuIo2Dxe. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PciCpuIo2Initialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiCpuIo2ProtocolGuid, &mCpuIo2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
new file mode 100644
index 0000000000..a3f8cf7cbb
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.h
@@ -0,0 +1,219 @@
+/** @file
+ Internal include file for the CPU I/O 2 Protocol.
+
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCI_CPU_IO2_DXE_H_
+#define PCI_CPU_IO2_DXE_H_
+
+//#include <PiDxe.h>
+//
+//#include <Protocol/CpuIo2.h>
+//
+//#include <Library/BaseLib.h>
+//#include <Library/DebugLib.h>
+//#include <Library/IoLib.h>
+//#include <Library/UefiBootServicesTableLib.h>
+
+#define MAX_IO_PORT_ADDRESS 0xFFFF
+
+/**
+ Reads memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+ IN EFI_CPU_IO2_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
new file mode 100644
index 0000000000..9fb7160ae7
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
@@ -0,0 +1,40 @@
+## @file
+# Produces the CPU I/O 2 Protocol by using the services of the I/O Library.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciCpuIo2Dxe
+ FILE_GUID = 168D1A6E-F4A5-448A-9E95-795661BB3067
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciCpuIo2Initialize
+
+[Sources]
+ PciCpuIo2Dxe.c
+
+[Packages]
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ DebugLib
+ IoLib
+ PcdLib
+ UefiBootServicesTableLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (9 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib xianglai
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
This driver produces Timer Architectural Protocol,
Registers a timer interrupt and initializes the timer.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Drivers/StableTimerDxe/Timer.c | 405 ++++++++++++++++++
.../Drivers/StableTimerDxe/Timer.h | 166 +++++++
.../Drivers/StableTimerDxe/TimerDxe.inf | 40 ++
3 files changed, 611 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
new file mode 100644
index 0000000000..29e10566b5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.c
@@ -0,0 +1,405 @@
+/** @file
+ Timer Architectural Protocol as defined in the DXE CIS
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Protocol/Cpu.h>
+#include "Library/Cpu.h"
+#include <Library/DebugLib.h>
+#include <Library/StableTimer.h>
+#include "Timer.h"
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+//
+// The handle onto which the Timer Architectural Protocol will be installed
+//
+EFI_HANDLE mTimerHandle = NULL;
+EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;
+
+//
+// The Timer Architectural Protocol that this driver produces
+//
+EFI_TIMER_ARCH_PROTOCOL mTimer = {
+ TimerDriverRegisterHandler,
+ TimerDriverSetTimerPeriod,
+ TimerDriverGetTimerPeriod,
+ TimerDriverGenerateSoftInterrupt
+};
+
+//
+// Pointer to the CPU Architectural Protocol instance
+//
+EFI_CPU_ARCH_PROTOCOL *mCpu;
+
+//
+// The notification function to call on every timer interrupt.
+// A bug in the compiler prevents us from initializing this here.
+//
+EFI_TIMER_NOTIFY mTimerNotifyFunction;
+
+//
+// The current period of the timer interrupt
+//
+volatile UINT64 mTimerPeriod = 0;
+volatile UINT64 mTimerTicks = 0;
+
+//
+// Const frequence in Hz
+//
+extern UINT32 StableTimerFreq;
+
+/**
+ Sets the counter value for timer.
+
+ @param Count The 16-bit counter value to program into stable timer.
+
+ @retval VOID
+**/
+VOID
+SetPitCount (
+ IN UINT64 Count
+ )
+{
+ if (Count <= 4) {
+ return;
+ }
+
+ Count &= LOONGARCH_CSR_TMCFG_TIMEVAL;
+ Count |= LOONGARCH_CSR_TMCFG_EN | LOONGARCH_CSR_TMCFG_PERIOD;
+ LOONGARCH_CSR_WRITEQ (Count, LOONGARCH_CSR_TMCFG);
+}
+
+/**
+ 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.
+ //
+ LOONGARCH_CSR_WRITEQ (0x1, LOONGARCH_CSR_TINTCLR);
+
+ if (mTimerNotifyFunction != NULL) {
+ //
+ // @bug : This does not handle missed timer interrupts
+ //
+ mTimerNotifyFunction (mTimerPeriod);
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+}
+
+/**
+
+ This function registers the handler NotifyFunction so it is called every time
+ the timer interrupt fires. It also passes the amount of time since the last
+ handler call to the NotifyFunction. If NotifyFunction is NULL, then the
+ handler is unregistered. If the handler is registered, then EFI_SUCCESS is
+ returned. If the CPU does not support registering a timer interrupt handler,
+ then EFI_UNSUPPORTED is returned. If an attempt is made to register a handler
+ when a handler is already registered, then EFI_ALREADY_STARTED is returned.
+ If an attempt is made to unregister a handler when a handler is not registered,
+ then EFI_INVALID_PARAMETER is returned. If an error occurs attempting to
+ register the NotifyFunction with the timer interrupt, then EFI_DEVICE_ERROR
+ is returned.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param NotifyFunction The function to call when a timer interrupt fires. This
+ function executes at TPL_HIGH_LEVEL. The DXE Core will
+ register a handler for the timer interrupt, so it can know
+ how much time has passed. This information is used to
+ signal timer based events. NULL will unregister the handler.
+
+ @retval EFI_SUCCESS The timer handler was registered.
+ @retval EFI_UNSUPPORTED The platform does not support timer interrupts.
+ @retval EFI_ALREADY_STARTED NotifyFunction is not NULL, and a handler is already
+ registered.
+ @retval EFI_INVALID_PARAMETER NotifyFunction is NULL, and a handler was not
+ previously registered.
+ @retval EFI_DEVICE_ERROR The timer handler could not be registered.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ IN EFI_TIMER_NOTIFY NotifyFunction
+ )
+{
+ //
+ // Check for invalid parameters
+ //
+ if ((NotifyFunction == NULL)
+ && (mTimerNotifyFunction == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((NotifyFunction != NULL)
+ && mTimerNotifyFunction != NULL)
+ {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mTimerNotifyFunction = NotifyFunction;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function adjusts the period of timer interrupts to the value specified
+ by TimerPeriod. If the timer period is updated, then the selected timer
+ period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+ If an error occurs while attempting to update the timer period, then the
+ timer hardware will be put back in its state prior to this call, and
+ EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt
+ is disabled. This is not the same as disabling the CPU's interrupts.
+ Instead, it must either turn off the timer hardware, or it must adjust the
+ interrupt controller so that a CPU interrupt is not generated when the timer
+ interrupt fires.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is
+ returned. If the timer is programmable, then the timer period
+ will be rounded up to the nearest timer period that is supported
+ by the timer hardware. If TimerPeriod is set to 0, then the
+ timer interrupts will be disabled.
+
+ @retval EFI_SUCCESS The timer period was changed.
+ @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt.
+ @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 TimerPeriod
+ )
+{
+ UINT64 TimerCount;
+
+ if (TimerPeriod == 0) {
+ //
+ // Disable timer interrupt for a TimerPeriod of 0
+ //
+ mCpu->DisableInterrupt (mCpu);
+ } else {
+
+ TimerCount = TimerPeriod * StableTimerFreq / 10000000ULL;
+
+ if (TimerCount >= BIT48) {
+ TimerCount = 0;
+ }
+
+ //
+ // Program the stable timer with the new count value
+ //
+ mTimerTicks = TimerCount;
+ SetPitCount (TimerCount);
+
+ //
+ // Enable timer interrupt
+ //
+ mCpu->EnableInterrupt (mCpu);
+ }
+
+ //
+ // Save the new timer period
+ //
+ mTimerPeriod = TimerPeriod;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function retrieves the period of timer interrupts in 100 ns units,
+ returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod
+ is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is
+ returned, then the timer is currently disabled.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If
+ 0 is returned, then the timer is currently disabled.
+
+ @retval EFI_SUCCESS The timer period was returned in TimerPeriod.
+ @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ OUT UINT64 *TimerPeriod
+ )
+{
+ if (TimerPeriod == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TimerPeriod = mTimerPeriod;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disable the timer
+**/
+
+/**
+ 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
+ */
+ LOONGARCH_CSR_WRITEQ (0, LOONGARCH_CSR_TMCFG);
+}
+
+/**
+
+ This function generates a soft timer interrupt. If the platform does not support soft
+ timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+ If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler ()
+ service, then a soft timer interrupt will be generated. If the timer interrupt is
+ enabled when this service is called, then the registered handler will be invoked. The
+ registered handler should not be able to distinguish a hardware-generated timer
+ interrupt from a software-generated timer interrupt.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The soft timer interrupt was generated.
+ @retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+ IN EFI_TIMER_ARCH_PROTOCOL *This
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initialize the Timer Architectural Protocol driver
+
+ @param ImageHandle ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Timer Architectural Protocol created
+ @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
+ @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+StableTimerDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TimerVector;
+
+ //
+ // Initialize the pointer to our notify function.
+ //
+ mTimerNotifyFunction = NULL;
+
+ //
+ // Make sure the Timer Architectural Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid);
+
+ //
+ // Find the CPU architectural protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Force the timer to be disabled
+ //
+ Status = TimerDriverSetTimerPeriod (&mTimer, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Calculate const frequence
+ //
+ StableTimerFreq = CalcConstFreq ();
+ DEBUG ((DEBUG_INFO, "===========Stable timer freq %d Hz=============\n", StableTimerFreq));
+
+ //
+ // Install interrupt handler for Stable Timer #0 (ISA IRQ0)
+ //
+ TimerVector = 0;
+ Status = mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerInterruptHandler);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Enable TI local timer interrupt
+ //
+ CpuSetIP (1 << 11);
+
+ //
+ // Force the timer to be enabled at its default period
+ //
+ Status = TimerDriverSetTimerPeriod (&mTimer, DEFAULT_TIMER_TICK_DURATION);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the Timer Architectural Protocol onto a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mTimerHandle,
+ &gEfiTimerArchProtocolGuid, &mTimer,
+ NULL
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ // Register for an ExitBootServicesEvent
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL,
+ &EfiExitBootServicesEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
new file mode 100644
index 0000000000..acc699b41b
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/Timer.h
@@ -0,0 +1,166 @@
+/** @file
+ Private data structures
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef TIMER_H_
+#define TIMER_H_
+
+#include <Protocol/Timer.h>
+
+
+#define DEFAULT_TIMER_TICK_DURATION 100000 //10ms = 100000 100 ns units
+#define SR_IP7 (1 << 15)
+//
+// Function Prototypes
+//
+
+extern UINT32 EFIAPI CpuGetCompare(VOID);
+extern VOID EFIAPI CpuSetCompare(IN UINT32 val);
+extern VOID EFIAPI CpuSetIP(IN UINT32 val);
+extern VOID EFIAPI ClearC0Cause(IN UINT32 val);
+extern VOID EFIAPI ClearC0Status(IN UINT32 val);
+/**
+ Initialize the Timer Architectural Protocol driver
+
+ @param ImageHandle ImageHandle of the loaded driver
+ @param SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Timer Architectural Protocol created
+ @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
+ @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+/**
+
+ This function adjusts the period of timer interrupts to the value specified
+ by TimerPeriod. If the timer period is updated, then the selected timer
+ period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+ If an error occurs while attempting to update the timer period, then the
+ timer hardware will be put back in its state prior to this call, and
+ EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt
+ is disabled. This is not the same as disabling the CPU's interrupts.
+ Instead, it must either turn off the timer hardware, or it must adjust the
+ interrupt controller so that a CPU interrupt is not generated when the timer
+ interrupt fires.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param NotifyFunction The rate to program the timer interrupt in 100 nS units. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is
+ returned. If the timer is programmable, then the timer period
+ will be rounded up to the nearest timer period that is supported
+ by the timer hardware. If TimerPeriod is set to 0, then the
+ timer interrupts will be disabled.
+
+ @retval EFI_SUCCESS The timer period was changed.
+ @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt.
+ @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverRegisterHandler (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ IN EFI_TIMER_NOTIFY NotifyFunction
+ )
+;
+
+/**
+
+ This function adjusts the period of timer interrupts to the value specified
+ by TimerPeriod. If the timer period is updated, then the selected timer
+ period is stored in EFI_TIMER.TimerPeriod, and EFI_SUCCESS is returned. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is returned.
+ If an error occurs while attempting to update the timer period, then the
+ timer hardware will be put back in its state prior to this call, and
+ EFI_DEVICE_ERROR is returned. If TimerPeriod is 0, then the timer interrupt
+ is disabled. This is not the same as disabling the CPU's interrupts.
+ Instead, it must either turn off the timer hardware, or it must adjust the
+ interrupt controller so that a CPU interrupt is not generated when the timer
+ interrupt fires.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod The rate to program the timer interrupt in 100 nS units. If
+ the timer hardware is not programmable, then EFI_UNSUPPORTED is
+ returned. If the timer is programmable, then the timer period
+ will be rounded up to the nearest timer period that is supported
+ by the timer hardware. If TimerPeriod is set to 0, then the
+ timer interrupts will be disabled.
+
+ @retval EFI_SUCCESS The timer period was changed.
+ @retval EFI_UNSUPPORTED The platform cannot change the period of the timer interrupt.
+ @retval EFI_DEVICE_ERROR The timer period could not be changed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverSetTimerPeriod (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ IN UINT64 TimerPeriod
+ )
+;
+
+/**
+
+ This function retrieves the period of timer interrupts in 100 ns units,
+ returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod
+ is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is
+ returned, then the timer is currently disabled.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+ @param TimerPeriod A pointer to the timer period to retrieve in 100 ns units. If
+ 0 is returned, then the timer is currently disabled.
+
+ @retval EFI_SUCCESS The timer period was returned in TimerPeriod.
+ @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGetTimerPeriod (
+ IN EFI_TIMER_ARCH_PROTOCOL *This,
+ OUT UINT64 *TimerPeriod
+ )
+;
+
+/**
+
+ This function generates a soft timer interrupt. If the platform does not support soft
+ timer interrupts, then EFI_UNSUPPORTED is returned. Otherwise, EFI_SUCCESS is returned.
+ If a handler has been registered through the EFI_TIMER_ARCH_PROTOCOL.RegisterHandler()
+ service, then a soft timer interrupt will be generated. If the timer interrupt is
+ enabled when this service is called, then the registered handler will be invoked. The
+ registered handler should not be able to distinguish a hardware-generated timer
+ interrupt from a software-generated timer interrupt.
+
+
+ @param This The EFI_TIMER_ARCH_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The soft timer interrupt was generated.
+ @retval EFI_UNSUPPORTED The platform does not support the generation of soft timer interrupts.
+
+**/
+EFI_STATUS
+EFIAPI
+TimerDriverGenerateSoftInterrupt (
+ IN EFI_TIMER_ARCH_PROTOCOL *This
+ )
+;
+
+#endif
diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
new file mode 100644
index 0000000000..10e6b9a85e
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
@@ -0,0 +1,40 @@
+## @file
+# Stable timer driver that provides Timer Arch protocol.
+#
+# Copyright (c) 2021 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
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ DebugLib
+ UefiDriverEntryPoint
+ IoLib
+ TimerLib
+
+[Sources]
+ Timer.h
+ Timer.c
+
+[Protocols]
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiTimerArchProtocolGuid ## PRODUCES
+
+[depex]
+ TRUE
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (10 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
This library provides interfaces such as
real-time clock initialization
to get time and setting time.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../LsRealTimeClockLib/LsRealTimeClock.h | 41 +++
.../LsRealTimeClockLib/LsRealTimeClockLib.c | 343 ++++++++++++++++++
.../LsRealTimeClockLib/LsRealTimeClockLib.inf | 41 +++
3 files changed, 425 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
new file mode 100644
index 0000000000..74a5c629ab
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClock.h
@@ -0,0 +1,41 @@
+/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Copyright (c) 2021, Loongson Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef LS_REAL_TIME_CLOCK_H_
+#define LS_REAL_TIME_CLOCK_H_
+
+#define TOY_WRITE0_REG 0x24
+#define TOY_WRITE1_REG 0x28
+#define TOY_READ0_REG 0x2c
+#define TOY_READ1_REG 0x30
+#define RTC_CTRL_REG 0x40
+
+/* TOY Enable bits */
+#define RTC_ENABLE_BIT (1UL << 13)
+#define TOY_ENABLE_BIT (1UL << 11)
+#define OSC_ENABLE_BIT (1UL << 8)
+
+/*
+ * shift bits and filed mask
+ */
+#define TOY_MON_MASK 0x3f
+#define TOY_DAY_MASK 0x1f
+#define TOY_HOUR_MASK 0x1f
+#define TOY_MIN_MASK 0x3f
+#define TOY_SEC_MASK 0x3f
+#define TOY_MSEC_MASK 0xf
+
+#define TOY_MON_SHIFT 26
+#define TOY_DAY_SHIFT 21
+#define TOY_HOUR_SHIFT 16
+#define TOY_MIN_SHIFT 10
+#define TOY_SEC_SHIFT 4
+
+#endif //__LS_REAL_TIME_CLOCK_H__
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
new file mode 100644
index 0000000000..cc5e426f03
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.c
@@ -0,0 +1,343 @@
+/** @file
+ Implement EFI RealTimeClock runtime services via RTC Lib.
+
+ Copyright (c) 2021, Loongson Limited. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/GlobalVariable.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/RealTimeClockLib.h>
+#include <Library/TimeBaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/RealTimeClock.h>
+#include "LsRealTimeClock.h"
+
+STATIC BOOLEAN mInitialized = FALSE;
+STATIC EFI_EVENT mRtcVirtualAddrChangeEvent;
+STATIC UINTN mRtcBase = 0X100d0100;
+/*
+ Enable Real-time clock.
+
+ @param VOID
+
+ @retval VOID
+ */
+VOID
+InitRtc (
+ VOID
+ )
+{
+ UINTN Val;
+
+ if (!mInitialized) {
+ /* enable rtc */
+ Val = MmioRead32 (mRtcBase + RTC_CTRL_REG);
+ Val |= TOY_ENABLE_BIT | OSC_ENABLE_BIT;
+ MmioWrite32 (mRtcBase + RTC_CTRL_REG, Val);
+ mInitialized = TRUE;
+ }
+}
+
+/**
+ Returns the current time and date information, and the time-keeping capabilities
+ of the hardware platform.
+
+ @param Time A pointer to storage to receive a snapshot of the current time.
+ @param Capabilities An optional pointer to a buffer to receive the real time clock
+ device's capabilities.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Time is NULL.
+ @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.
+ @retval EFI_SECURITY_VIOLATION The time could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities
+ )
+{
+ UINT32 Val;
+
+ // Ensure Time is a valid pointer
+ if (Time == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ InitRtc ();
+ Val = MmioRead32 (mRtcBase + TOY_READ1_REG);
+ Time->Year = Val + 1900;
+
+ Val = MmioRead32 (mRtcBase + TOY_READ0_REG);
+ Time->Month = ((Val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1;
+ Time->Day = (Val >> TOY_DAY_SHIFT) & TOY_DAY_MASK;
+ Time->Hour = (Val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
+ Time->Minute = (Val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
+ Time->Second = (Val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
+ Time->Nanosecond = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sets the current local time and date information.
+
+ @param Time A pointer to the current time.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+ IN EFI_TIME *Time
+ )
+{
+ UINT32 Val;
+
+ // Initialize the hardware if not already done
+ InitRtc ();
+
+ Val = 0;
+ Val |= (Time->Second << TOY_SEC_SHIFT);
+ Val |= (Time->Minute << TOY_MIN_SHIFT);
+ Val |= (Time->Hour << TOY_HOUR_SHIFT);
+ Val |= (Time->Day << TOY_DAY_SHIFT);
+ Val |= ((Time->Month + 1) << TOY_MON_SHIFT);
+ MmioWrite32 (mRtcBase + TOY_WRITE0_REG, Val);
+
+ Val = Time->Year - 1900;
+ MmioWrite32 (mRtcBase + TOY_WRITE1_REG, Val);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the current wakeup alarm clock setting.
+
+ @param Enabled Indicates if the alarm is currently enabled or disabled.
+ @param Pending Indicates if the alarm signal is pending and requires acknowledgement.
+ @param Time The current alarm setting.
+
+ @retval EFI_SUCCESS The alarm settings were returned.
+ @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+ OUT BOOLEAN *Enabled,
+ OUT BOOLEAN *Pending,
+ OUT EFI_TIME *Time
+ )
+{
+ // Not a required feature
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Sets the system wakeup alarm clock time.
+
+ @param Enabled Enable or disable the wakeup alarm.
+ @param Time If Enable is TRUE, the time to set the wakeup alarm for.
+
+ @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled. If
+ Enable is FALSE, then the wakeup alarm was disabled.
+ @retval EFI_INVALID_PARAMETER A time field is out of range.
+ @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.
+ @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+ IN BOOLEAN Enabled,
+ OUT EFI_TIME *Time
+ )
+{
+ // Not a required feature
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Only needed if you are going to support the OS calling RTC functions in virtual mode.
+ // You will need to call EfiConvertPointer (). To convert any stored physical addresses
+ // to virtual address. After the OS transitions to calling in virtual mode, all future
+ // runtime calls will be made in virtual mode.
+ //
+ EfiConvertPointer (0x0, (VOID**)&mRtcBase);
+ return;
+}
+
+/** Add the RTC controller address range to the memory map.
+
+ @param [in] ImageHandle The handle to the image.
+ @param [in] RtcPageBase Base address of the RTC controller.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Flash device not found.
+**/
+EFI_STATUS
+KvmtoolRtcMapMemory (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_PHYSICAL_ADDRESS RtcPageBase
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ RtcPageBase,
+ EFI_PAGE_SIZE,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR, "Failed to add memory space. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ EFI_PAGE_SIZE,
+ &RtcPageBase,
+ ImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Failed to allocate memory space. Status = %r\n",
+ Status
+ ));
+ gDS->RemoveMemorySpace (
+ RtcPageBase,
+ EFI_PAGE_SIZE
+ );
+ return Status;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (
+ RtcPageBase,
+ EFI_PAGE_SIZE,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Failed to set memory attributes. Status = %r\n",
+ Status
+ ));
+
+ gDS->FreeMemorySpace (
+ RtcPageBase,
+ EFI_PAGE_SIZE
+ );
+
+ gDS->RemoveMemorySpace (
+ RtcPageBase,
+ EFI_PAGE_SIZE
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This is the declaration of an EFI image entry point. This can be the entry point to an application
+ written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Status = KvmtoolRtcMapMemory (ImageHandle, (mRtcBase & ~EFI_PAGE_MASK));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "Failed to map memory for loongson 7A RTC. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Setup the setters and getters
+ gRT->GetTime = LibGetTime;
+ gRT->SetTime = LibSetTime;
+
+ // Install the protocol
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiRealTimeClockArchProtocolGuid, NULL,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ LibRtcVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mRtcVirtualAddrChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
new file mode 100644
index 0000000000..c985f7a727
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
@@ -0,0 +1,41 @@
+## @file
+#
+# Copyright (c) 2021, Loongson Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LsRealTimeClockLib
+ FILE_GUID = 9793a3da-1869-4fdf-88b1-c6484341f50b
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RealTimeClockLib
+
+[Sources.common]
+ LsRealTimeClockLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ IoLib
+ UefiLib
+ DebugLib
+ PcdLib
+ DxeServicesTableLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gEfiRealTimeClockArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Depex]
+ TRUE
+
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (11 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 14/15] Platform/Loongson: Add Reset System Lib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 15/15] Platform/Loongson: Support Dxe xianglai
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
The Library provides Boot Manager interfaces.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../PlatformBootManagerLib/PlatformBm.c | 761 ++++++++++++++++++
.../PlatformBootManagerLib/PlatformBm.h | 126 +++
.../PlatformBootManagerLib.inf | 78 ++
.../PlatformBootManagerLib/QemuKernel.c | 449 +++++++++++
4 files changed, 1414 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
new file mode 100644
index 0000000000..1805a6a9b3
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.c
@@ -0,0 +1,761 @@
+/** @file
+ Implementation for PlatformBootManagerLib library class interfaces.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Pci22.h>
+#include <Library/BootLogoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/QemuBootOrderLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "PlatformBm.h"
+
+STATIC PLATFORM_SERIAL_CONSOLE mSerialConsole = {
+ //
+ // VENDOR_DEVICE_PATH SerialDxe
+ //
+ {
+ { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, DP_NODE_LEN (VENDOR_DEVICE_PATH) },
+ SERIAL_DXE_FILE_GUID
+ },
+
+ //
+ // UART_DEVICE_PATH Uart
+ //
+ {
+ { MESSAGING_DEVICE_PATH, MSG_UART_DP, DP_NODE_LEN (UART_DEVICE_PATH) },
+ 0, // Reserved
+ FixedPcdGet64 (PcdUartDefaultBaudRate), // BaudRate
+ FixedPcdGet8 (PcdUartDefaultDataBits), // DataBits
+ FixedPcdGet8 (PcdUartDefaultParity), // Parity
+ FixedPcdGet8 (PcdUartDefaultStopBits) // StopBits
+ },
+
+ //
+ // VENDOR_DEFINED_DEVICE_PATH TermType
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_VENDOR_DP,
+ DP_NODE_LEN (VENDOR_DEFINED_DEVICE_PATH)
+ }
+ //
+ // Guid to be filled in dynamically
+ //
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+STATIC PLATFORM_USB_KEYBOARD mUsbKeyboard = {
+ //
+ // USB_CLASS_DEVICE_PATH Keyboard
+ //
+ {
+ {
+ MESSAGING_DEVICE_PATH, MSG_USB_CLASS_DP,
+ DP_NODE_LEN (USB_CLASS_DEVICE_PATH)
+ },
+ 0xFFFF, // VendorId: any
+ 0xFFFF, // ProductId: any
+ 3, // DeviceClass: HID
+ 1, // DeviceSubClass: boot
+ 1 // DeviceProtocol: keyboard
+ },
+
+ //
+ // EFI_DEVICE_PATH_PROTOCOL End
+ //
+ {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ DP_NODE_LEN (EFI_DEVICE_PATH_PROTOCOL)
+ }
+};
+
+/**
+ Locate all handles that carry the specified protocol, filter them with a
+ callback function, and pass each handle that passes the filter to another
+ callback.
+
+ @param[in] ProtocolGuid The protocol to look for.
+
+ @param[in] Filter The filter function to pass each handle to. If this
+ parameter is NULL, then all handles are processed.
+
+ @param[in] Process The callback function to pass each handle to that
+ clears the filter.
+**/
+VOID
+FilterAndProcess (
+ IN EFI_GUID *ProtocolGuid,
+ IN FILTER_FUNCTION Filter OPTIONAL,
+ IN CALLBACK_FUNCTION Process
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ UINTN Idx;
+
+ Status = gBS->LocateHandleBuffer (ByProtocol, ProtocolGuid,
+ NULL /* SearchKey */, &NoHandles, &Handles);
+ if (EFI_ERROR (Status)) {
+ //
+ // This is not an error, just an informative condition.
+ //
+ DEBUG ((DEBUG_VERBOSE, "%a: %g: %r\n", __FUNCTION__, ProtocolGuid,
+ Status));
+ return;
+ }
+
+ ASSERT (NoHandles > 0);
+ for (Idx = 0; Idx < NoHandles; ++Idx) {
+ CHAR16 *DevicePathText;
+ STATIC CHAR16 Fallback[] = L"<device path unavailable>";
+
+ //
+ // The ConvertDevicePathToText () function handles NULL input transparently.
+ //
+ DevicePathText = ConvertDevicePathToText (
+ DevicePathFromHandle (Handles[Idx]),
+ FALSE, // DisplayOnly
+ FALSE // AllowShortcuts
+ );
+ if (DevicePathText == NULL) {
+ DevicePathText = Fallback;
+ }
+
+ if ((Filter == NULL)
+ || (Filter (Handles[Idx], DevicePathText)))
+ {
+ Process (Handles[Idx], DevicePathText);
+ }
+
+ if (DevicePathText != Fallback) {
+ FreePool (DevicePathText);
+ }
+ }
+ gBS->FreePool (Handles);
+}
+
+
+/**
+ This FILTER_FUNCTION checks if a handle corresponds to a PCI display device.
+
+ @param Handle The handle to check
+ @param ReportText A pointer to a string at the time of the error.
+
+ @retval TURE THe handle corresponds to a PCI display device.
+ @retval FALSE THe handle does not corresponds to a PCI display device.
+**/
+BOOLEAN
+EFIAPI
+IsPciDisplay (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ Status = gBS->HandleProtocol (Handle, &gEfiPciIoProtocolGuid,
+ (VOID**)&PciIo);
+ if (EFI_ERROR (Status)) {
+ //
+ // This is not an error worth reporting.
+ //
+ return FALSE;
+ }
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0 /* Offset */,
+ sizeof Pci / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: %r\n", __FUNCTION__, ReportText, Status));
+ return FALSE;
+ }
+
+ return IS_PCI_DISPLAY (&Pci);
+}
+
+
+/**
+ This CALLBACK_FUNCTION attempts to connect a handle non-recursively, asking
+ the matching driver to produce all first-level child handles.
+
+ @param Handle The handle to connect.
+ @param ReportText A pointer to a string at the time of the error.
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+Connect (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->ConnectController (
+ Handle, // ControllerHandle
+ NULL, // DriverImageHandle
+ NULL, // RemainingDevicePath -- produce all children
+ FALSE // Recursive
+ );
+ DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE, "%a: %s: %r\n",
+ __FUNCTION__, ReportText, Status));
+}
+
+
+/**
+ This CALLBACK_FUNCTION retrieves the EFI_DEVICE_PATH_PROTOCOL from the
+ handle, and adds it to ConOut and ErrOut.
+
+ @param Handle The handle to retrieves.
+ @param ReportText A pointer to a string at the time of the error.
+
+ @retval VOID
+**/
+VOID
+EFIAPI
+AddOutput (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: handle %p: device path not found\n",
+ __FUNCTION__, ReportText, Handle));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ConOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ConOut: %r\n", __FUNCTION__,
+ ReportText, Status));
+ return;
+ }
+
+ Status = EfiBootManagerUpdateConsoleVariable (ErrOut, DevicePath, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: %s: adding to ErrOut: %r\n", __FUNCTION__,
+ ReportText, Status));
+ return;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a: %s: added to ConOut and ErrOut\n", __FUNCTION__,
+ ReportText));
+}
+/**
+ Register the boot option.
+
+ @param FileGuid File Guid.
+ @param Description Option descriptor.
+ @param Attributes Option Attributes.
+
+ @retval VOID
+**/
+VOID
+PlatformRegisterFvBootOption (
+ IN EFI_GUID *FileGuid,
+ IN CHAR16 *Description,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ INTN OptionIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
+ DevicePath = DevicePathFromHandle (LoadedImage->DeviceHandle);
+ ASSERT (DevicePath != NULL);
+ DevicePath = AppendDevicePathNode (
+ DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
+ );
+ ASSERT (DevicePath != NULL);
+
+ Status = EfiBootManagerInitializeLoadOption (
+ &NewOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ Attributes,
+ Description,
+ DevicePath,
+ NULL,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DevicePath);
+
+ BootOptions = EfiBootManagerGetLoadOptions (
+ &BootOptionCount, LoadOptionTypeBoot
+ );
+
+ OptionIndex = EfiBootManagerFindLoadOption (
+ &NewOption, BootOptions, BootOptionCount
+ );
+
+ if (OptionIndex == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&NewOption, MAX_UINTN);
+ ASSERT_EFI_ERROR (Status);
+ }
+ EfiBootManagerFreeLoadOption (&NewOption);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+
+/**
+ Remove all MemoryMapped (...)/FvFile (...) and Fv (...)/FvFile (...) boot options
+ whose device paths do not resolve exactly to an FvFile in the system.
+
+ This removes any boot options that point to binaries built into the firmware
+ and have become stale due to any of the following:
+ - FvMain's base address or size changed (historical),
+ - FvMain's FvNameGuid changed,
+ - the FILE_GUID of the pointed-to binary changed,
+ - the referenced binary is no longer built into the firmware.
+
+ EfiBootManagerFindLoadOption () used in PlatformRegisterFvBootOption () only
+ avoids exact duplicates.
+**/
+VOID
+RemoveStaleFvFileOptions (
+ VOID
+ )
+{
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ UINTN Index;
+
+ BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,
+ LoadOptionTypeBoot);
+
+ for (Index = 0; Index < BootOptionCount; ++Index) {
+ EFI_DEVICE_PATH_PROTOCOL *Node1, *Node2, *SearchNode;
+ EFI_STATUS Status;
+ EFI_HANDLE FvHandle;
+
+ //
+ // If the device path starts with neither MemoryMapped (...) nor Fv (...),
+ // then keep the boot option.
+ //
+ Node1 = BootOptions[Index].FilePath;
+ if (!(DevicePathType (Node1) == HARDWARE_DEVICE_PATH
+ && DevicePathSubType (Node1) == HW_MEMMAP_DP)
+ && !(DevicePathType (Node1) == MEDIA_DEVICE_PATH
+ && DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP))
+ {
+ continue;
+ }
+
+ //
+ // If the second device path node is not FvFile (...), then keep the boot
+ // option.
+ //
+ Node2 = NextDevicePathNode (Node1);
+ if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH)
+ || (DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP))
+ {
+ continue;
+ }
+
+ //
+ // Locate the Firmware Volume2 protocol instance that is denoted by the
+ // boot option. If this lookup fails (i.e., the boot option references a
+ // firmware volume that doesn't exist), then we'll proceed to delete the
+ // boot option.
+ //
+ SearchNode = Node1;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid,
+ &SearchNode, &FvHandle);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The firmware volume was found; now let's see if it contains the FvFile
+ // identified by GUID.
+ //
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFileNode;
+ UINTN BufferSize;
+ EFI_FV_FILETYPE FoundType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINT32 AuthenticationStatus;
+
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **)&FvProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ FvFileNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)Node2;
+ //
+ // Buffer==NULL means we request metadata only: BufferSize, FoundType,
+ // FileAttributes.
+ //
+ Status = FvProtocol->ReadFile (
+ FvProtocol,
+ &FvFileNode->FvFileName, // NameGuid
+ NULL, // Buffer
+ &BufferSize,
+ &FoundType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The FvFile was found. Keep the boot option.
+ //
+ continue;
+ }
+ }
+
+ //
+ // Delete the boot option.
+ //
+ Status = EfiBootManagerDeleteLoadOptionVariable (
+ BootOptions[Index].OptionNumber, LoadOptionTypeBoot);
+ DEBUG_CODE (
+ CHAR16 *DevicePathString;
+
+ DevicePathString = ConvertDevicePathToText (BootOptions[Index].FilePath,
+ FALSE, FALSE);
+ DEBUG ((
+ EFI_ERROR (Status) ? EFI_D_WARN : DEBUG_VERBOSE,
+ "%a: removing stale Boot#%04x %s: %r\n",
+ __FUNCTION__,
+ (UINT32)BootOptions[Index].OptionNumber,
+ DevicePathString == NULL ? L"<unavailable>" : DevicePathString,
+ Status
+ ));
+ if (DevicePathString != NULL) {
+ FreePool (DevicePathString);
+ }
+ );
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+}
+
+/**
+ Register the boot option And Keys.
+
+ @param VOID
+
+ @retval VOID
+**/
+VOID
+PlatformRegisterOptionsAndKeys (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Enter;
+ EFI_INPUT_KEY F2;
+ EFI_INPUT_KEY Esc;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ //
+ // Register ENTER as CONTINUE key
+ //
+ Enter.ScanCode = SCAN_NULL;
+ Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
+ Status = EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Map F2 and ESC to Boot Manager Menu
+ //
+ F2.ScanCode = SCAN_F2;
+ F2.UnicodeChar = CHAR_NULL;
+ Esc.ScanCode = SCAN_ESC;
+ Esc.UnicodeChar = CHAR_NULL;
+ Status = EfiBootManagerGetBootManagerMenu (&BootOption);
+ ASSERT_EFI_ERROR (Status);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+ Status = EfiBootManagerAddKeyOptionVariable (
+ NULL, (UINT16) BootOption.OptionNumber, 0, &Esc, NULL
+ );
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED);
+}
+
+
+//
+// BDS Platform Functions
+//
+/**
+ Do the platform init, can be customized by OEM/IBV
+ Possible things that can be done in PlatformBootManagerBeforeConsole:
+ > Update console variable: 1. include hot-plug devices;
+ > 2. Clear ConIn and add SOL for AMT
+ > Register new Driver#### or Boot####
+ > Register new Key####: e.g.: F12
+ > Signal ReadyToLock event
+ > Authentication action: 1. connect Auth devices;
+ > 2. Identify auto logon user.
+**/
+VOID
+EFIAPI
+PlatformBootManagerBeforeConsole (
+ VOID
+ )
+{
+ RETURN_STATUS PcdStatus;
+
+ //
+ // Signal EndOfDxe PI Event
+ //
+ EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
+
+ //
+ // Dispatch deferred images after EndOfDxe event.
+ //
+ EfiBootManagerDispatchDeferredImages ();
+
+ //
+ // Locate the PCI root bridges and make the PCI bus driver connect each,
+ // non-recursively. This will produce a number of child handles with PciIo on
+ // them.
+ //
+ FilterAndProcess (&gEfiPciRootBridgeIoProtocolGuid, NULL, Connect);
+
+ //
+ // Signal the ACPI platform driver that it can download QEMU ACPI tables.
+ //
+ EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);
+
+ //
+ // Find all display class PCI devices (using the handles from the previous
+ // step), and connect them non-recursively. This should produce a number of
+ // child handles with GOPs on them.
+ //
+ FilterAndProcess (&gEfiPciIoProtocolGuid, IsPciDisplay, Connect);
+
+ //
+ // Now add the device path of all handles with GOP on them to ConOut and
+ // ErrOut.
+ //
+ FilterAndProcess (&gEfiGraphicsOutputProtocolGuid, NULL, AddOutput);
+
+ //
+ // Add the hardcoded short-form USB keyboard device path to ConIn.
+ //
+ EfiBootManagerUpdateConsoleVariable (ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mUsbKeyboard, NULL);
+
+ //
+ // Add the hardcoded serial console device path to ConIn, ConOut, ErrOut.
+ //
+ CopyGuid (&mSerialConsole.TermType.Guid, &gEfiTtyTermGuid);
+ EfiBootManagerUpdateConsoleVariable (ConIn,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+ EfiBootManagerUpdateConsoleVariable (ConOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+ EfiBootManagerUpdateConsoleVariable (ErrOut,
+ (EFI_DEVICE_PATH_PROTOCOL *)&mSerialConsole, NULL);
+
+ //
+ // Set the front page timeout from the QEMU configuration.
+ //
+ PcdStatus = PcdSet16S (PcdPlatformBootTimeOut,
+ GetFrontPageTimeoutFromQemu ());
+ ASSERT_RETURN_ERROR (PcdStatus);
+
+ //
+ // Register platform-specific boot options and keyboard shortcuts.
+ //
+ PlatformRegisterOptionsAndKeys ();
+}
+
+/**
+ Do the platform specific action after the console is ready
+ Possible things that can be done in PlatformBootManagerAfterConsole:
+ > Console post action:
+ > Dynamically switch output mode from 100x31 to 80x25 for certain senarino
+ > Signal console ready platform customized event
+ > Run diagnostics like memory testing
+ > Connect certain devices
+ > Dispatch aditional option roms
+ > Special boot: e.g.: USB boot, enter UI
+**/
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ //
+ // Show the splash screen.
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ BootLogoEnableLogo ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+
+ //
+ // Connect the rest of the devices.
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ EfiBootManagerConnectAll ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+
+ SetBootParams ();
+ //
+ // Process QEMU's -kernel command line option. Note that the kernel booted
+ // this way should receive ACPI tables, which is why we connect all devices
+ // first (see above) -- PCI enumeration blocks ACPI table installation, if
+ // there is a PCI host.
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ TryRunningQemuKernel ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+
+ //
+ // Enumerate all possible boot options, then filter and reorder them based on
+ // the QEMU configuration.
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ EfiBootManagerRefreshAllBootOption ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+
+ //
+ // Register UEFI Shell
+ //
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+
+ RemoveStaleFvFileOptions ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+ SetBootOrderFromQemu ();
+ DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole, func: %a, line: %d\n", __func__, __LINE__));
+}
+
+/**
+ This function is called each second during the boot manager waits the
+ timeout.
+
+ @param TimeoutRemain The remaining timeout.
+**/
+VOID
+EFIAPI
+PlatformBootManagerWaitCallback (
+ IN UINT16 TimeoutRemain
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
+ UINT16 Timeout;
+
+ Timeout = PcdGet16 (PcdPlatformBootTimeOut);
+
+ Black.Raw = 0x00000000;
+ White.Raw = 0x00FFFFFF;
+
+ BootLogoUpdateProgress (
+ White.Pixel,
+ Black.Pixel,
+ L"Start boot option",
+ White.Pixel,
+ (Timeout - TimeoutRemain) * 100 / Timeout,
+ 0
+ );
+}
+
+/**
+ The function is called when no boot option could be launched,
+ including platform recovery options and options pointing to applications
+ built into firmware volumes.
+
+ If this function returns, BDS attempts to enter an infinite loop.
+**/
+VOID
+EFIAPI
+PlatformBootManagerUnableToBoot (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;
+ UINTN Index;
+
+ //
+ // BootManagerMenu doesn't contain the correct information when return status
+ // is EFI_NOT_FOUND.
+ //
+ Status = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ //
+ // Normally BdsDxe does not print anything to the system console, but this is
+ // a last resort -- the end-user will likely not see any DEBUG messages
+ // logged in this situation.
+ //
+ // AsciiPrint () will NULL-check gST->ConOut internally. We check gST->ConIn
+ // here to see if it makes sense to request and wait for a keypress.
+ //
+ if (gST->ConIn != NULL) {
+ AsciiPrint (
+ "%a: No bootable option or device was found.\n"
+ "%a: Press any key to enter the Boot Manager Menu.\n",
+ gEfiCallerBaseName,
+ gEfiCallerBaseName
+ );
+ Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (Index == 0);
+
+ //
+ // Drain any queued keys.
+ //
+ while (!EFI_ERROR (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key))) {
+ //
+ // just throw away Key
+ //
+ }
+ }
+
+ for (;;) {
+ EfiBootManagerBoot (&BootManagerMenu);
+ }
+}
+
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
new file mode 100644
index 0000000000..5b7dd20794
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBm.h
@@ -0,0 +1,126 @@
+/** @file
+ Head file for BDS Platform specific code
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PLATFORM_BM_H_
+#define PLATFORM_BM_H_
+
+#include <Library/DevicePathLib.h>
+
+#define DP_NODE_LEN(Type) { (UINT8)sizeof (Type), (UINT8)(sizeof (Type) >> 8) }
+
+#define SERIAL_DXE_FILE_GUID { \
+ 0xD3987D4B, 0x971A, 0x435F, \
+ { 0x8C, 0xAF, 0x49, 0x67, 0xEB, 0x62, 0x72, 0x41 } \
+ }
+
+#define ALIGN_UP(addr, align) \
+ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
+
+#pragma pack (1)
+typedef struct {
+ VENDOR_DEVICE_PATH SerialDxe;
+ UART_DEVICE_PATH Uart;
+ VENDOR_DEFINED_DEVICE_PATH TermType;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_SERIAL_CONSOLE;
+#pragma pack ()
+
+#pragma pack (1)
+typedef struct {
+ USB_CLASS_DEVICE_PATH Keyboard;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} PLATFORM_USB_KEYBOARD;
+#pragma pack ()
+
+/**
+ Check if the handle satisfies a particular condition.
+
+ @param[in] Handle The handle to check.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+
+ @retval TRUE The condition is satisfied.
+ @retval FALSE Otherwise. This includes the case when the condition could not
+ be fully evaluated due to an error.
+**/
+typedef
+BOOLEAN
+(EFIAPI *FILTER_FUNCTION) (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+/**
+ Process a handle.
+
+ @param[in] Handle The handle to process.
+ @param[in] ReportText A caller-allocated string passed in for reporting
+ purposes. It must never be NULL.
+**/
+typedef
+VOID
+(EFIAPI *CALLBACK_FUNCTION) (
+ IN EFI_HANDLE Handle,
+ IN CONST CHAR16 *ReportText
+ );
+
+/**
+ * execute from kernel entry point.
+ *
+ * @param[in] Argc The count of args.
+ * @param[in] Argv The pointer to args array.
+ * @param[in] Bpi The pointer to bootparaminterface struct.
+ * @param[in] Vec The fourth args for kernel.
+ ***/
+typedef
+VOID
+(EFIAPI *EFI_KERNEL_ENTRY_POINT) (
+ IN UINTN Argc,
+ IN VOID *Argv,
+ IN VOID *Bpi,
+ IN VOID *Vec
+ );
+
+/**
+ Download the kernel, the initial ramdisk, and the kernel command line from
+ QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+ image files, and load and start the kernel from it.
+
+ The kernel will be instructed via its command line to load the initrd from
+ the same Simple FileSystem.
+
+ @retval EFI_NOT_FOUND Kernel image was not found.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
+
+ @return Error codes from any of the underlying
+ functions. On success, the function doesn't
+ return.
+**/
+EFI_STATUS
+EFIAPI
+TryRunningQemuKernel (
+ VOID
+ );
+
+/*
+ Setup the boot parameter.
+
+ @param VOID
+
+ @retval EFI_SUCCESS The boot parameter was established successfully.
+ @retval EFI_INVALID_PARAMETER Input GUID is NULL.
+ @retval EFI_NOT_FOUND Attempted to delete non-existant entry
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available
+ */
+EFI_STATUS
+EFIAPI
+SetBootParams (VOID);
+
+#endif // _PLATFORM_BM_H_
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
new file mode 100644
index 0000000000..0242381fc5
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -0,0 +1,78 @@
+## @file
+# Implementation for PlatformBootManagerLib library class interfaces.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBootManagerLib
+ FILE_GUID = 469184E8-FADA-41E4-8823-012CA19B40D4
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBootManagerLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = LOONGARCH64
+#
+
+[Sources]
+ PlatformBm.c
+ QemuKernel.c
+
+[Packages]
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ OvmfPkg/OvmfPkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ BootLogoLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ PcdLib
+ PrintLib
+ QemuBootOrderLib
+ QemuFwCfgLib
+ UefiBootManagerLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ BpiLib
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+ gEfiEndOfDxeEventGroupGuid
+ gRootBridgesConnectedEventGroupGuid
+ gUefiShellFileGuid
+ gEfiLoongsonBootparamsTableGuid ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiTtyTermGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiGraphicsOutputProtocolGuid
+ gEfiLoadedImageProtocolGuid
+ gEfiPciRootBridgeIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
new file mode 100644
index 0000000000..bb25edcada
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/QemuKernel.c
@@ -0,0 +1,449 @@
+/** @file
+ Try to run Linux kernel.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - mem - Memory
+ - Bpi - Boot Parameter Interface
+ - FwCfg - FirmWare Configure
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/LoadLinuxLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/Bpi.h>
+#include <string.h>
+#include <Library/BaseMemoryLib.h>
+#include "PlatformBm.h"
+
+/*
+ Calculates the checksum.
+
+ @param buffer A pointer to the data to calculate the checksum.
+ @param length The number of data involved in calculating the checksum.
+
+ @retval the value of checksum.
+ */
+UINT8
+CalculateCheckSum8 (
+ IN CONST UINT8 *buffer, IN UINTN length
+ )
+{
+ UINT8 checksum;
+ UINTN count;
+
+ for (checksum = 0, count = 0; count < length; count++) {
+ checksum = (UINT8) (checksum + * (buffer + count));
+ }
+ return (UINT8) (0x100 - checksum);
+}
+/*
+ Iterates through all memory maps merging adjacent memory regions.
+
+ @param array A pointer to a memory-mapped table.
+ @param length The length of the memory-mapped table.
+ @param bpmem Adjusted memory information table.
+ @param index The Index of Adjusted memory information table.
+ @param memtype Specifies the memory type.
+
+ @retval the value of checksum.
+ */
+UINT32
+memmap_sort (
+ IN MEMMAP array[],
+ IN UINT32 length,
+ OUT MEM_MAP * bpmem,
+ IN UINT32 index,
+ IN UINT32 memtype
+ )
+{
+ UINT64 tempmemsize = 0;
+ UINT32 j = 0;
+ UINT32 t = 0;
+
+ for (j = 0; j < length; ) {
+ tempmemsize = array[j].MemSize;
+ for (t = j + 1; t < length; t++) {
+ if (array[j].MemStart + tempmemsize == array[t].MemStart) {
+ tempmemsize += array[t].MemSize;
+ } else {
+ break;
+ }
+ }
+
+ bpmem->Map[index].MemType = memtype;
+ bpmem->Map[index].MemStart = array[j].MemStart;
+ bpmem->Map[index].MemSize = tempmemsize;
+ DEBUG ((DEBUG_INFO, "map[%d]:type %x, start 0x%llx, end 0x%llx\n",
+ index,
+ bpmem->Map[index].MemType,
+ bpmem->Map[index].MemStart,
+ bpmem->Map[index].MemStart+ bpmem->Map[index].MemSize
+ ));
+ j = t;
+ index++;
+ }
+ return index;
+}
+/*
+ Look for memory-mapped information.
+
+ @param Bpi A pointer to the boot parameter interface.
+
+ @retval The address of the memory-mapped table.
+ */
+MEM_MAP *
+FindNewInterfaceMem (
+ IN BootParamsInterface *Bpi
+ )
+{
+ CHAR8 *p =NULL;
+ MEM_MAP *new_interface_mem = NULL;
+ EXT_LIST *listpointer = NULL;
+
+ if (Bpi == NULL) {
+ return new_interface_mem;
+ }
+
+ p = (CHAR8 *)& (Bpi->Signature);
+ if (AsciiStrnCmp (p, "BPI", 3) == 0) {
+ listpointer = Bpi->ExtList;
+ for (; listpointer != NULL; listpointer = listpointer->next) {
+ CHAR8 *pl = (CHAR8 *) & (listpointer->Signature);
+ if (AsciiStrnCmp (pl, "MEM", 3) == 0) {
+ new_interface_mem = (MEM_MAP *)listpointer;
+ }
+ }
+ }
+
+ return new_interface_mem;
+}
+/**
+ Gets the system memory mapping information.
+
+ @param MapKey memory-mapped key.
+ @param MemoryMapSize The size of the memory-mapped information.
+ @param DescriptorSize The size of the memory-mapped information descriptor.
+
+ @retval VOID
+**/
+EFI_MEMORY_DESCRIPTOR *
+GetSystemMemap (
+ OUT UINTN *MapKey,
+ OUT UINTN *MemoryMapSize,
+ OUT UINTN *DescriptorSize
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_MEMORY_DESCRIPTOR *MemoryMap = NULL;
+ UINTN MemoryMapSizeTemp = 0;
+ UINTN DescriptorSizeTemp = 0;
+ UINT8 TmpMemoryMap[1];
+ UINT32 DescriptorVersion = 0;
+
+ // Get System MemoryMapSize
+ MemoryMapSizeTemp = sizeof (TmpMemoryMap);
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSizeTemp,
+ (EFI_MEMORY_DESCRIPTOR *)TmpMemoryMap,
+ MapKey,
+ &DescriptorSizeTemp,
+ &DescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status));
+ // Enlarge space here, because we will allocate pool now.
+ MemoryMapSizeTemp += EFI_PAGE_SIZE;
+ Status = gBS->AllocatePool (
+ EfiLoaderData,
+ MemoryMapSizeTemp,
+ (VOID **) &MemoryMap
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status));
+
+ *MemoryMapSize = MemoryMapSizeTemp;
+ *DescriptorSize = DescriptorSizeTemp;
+ if (NULL == MemoryMap) {
+ return NULL;
+ }
+
+ // Get System MemoryMap
+ Status = gBS->GetMemoryMap (
+ &MemoryMapSizeTemp,
+ MemoryMap,
+ MapKey,
+ &DescriptorSizeTemp,
+ &DescriptorVersion
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "%a %a:%d Status 0x%x\n", __FILE__, __func__, __LINE__, Status));
+ *MemoryMapSize = MemoryMapSizeTemp;
+ *DescriptorSize = DescriptorSizeTemp;
+
+ return MemoryMap;
+}
+/**
+ Memory-mapped information is processed according to the different types
+ of memory in the memory-mapped table.
+
+ @param new_interface_mem A pointer to a memory-mapped table.
+ @param MemoryMapPtr A pointer to the memory descriptor struct.
+ @param MemoryMapSize The size of the memory-mapped table.
+ @param DescriptorSize The size of the descriptor.
+
+ @retval VOID
+**/
+VOID
+MemMapSort (
+ IN OUT MEM_MAP *new_interface_mem,
+ IN EFI_MEMORY_DESCRIPTOR *MemoryMapPtr,
+ IN UINTN MemoryMapSize,
+ IN UINTN DescriptorSize
+ )
+{
+ MEMMAP reserve_mem[MAX_MEM_MAP];
+ MEMMAP free_mem[MAX_MEM_MAP];
+ MEMMAP acpi_table_mem[MAX_MEM_MAP];
+ MEMMAP acpi_nvs_mem[MAX_MEM_MAP];
+ UINT32 free_index = 0;
+ UINT32 reserve_index = 0;
+ UINT32 acpi_table_index = 0;
+ UINT32 acpi_nvs_index = 0;
+ UINT64 tempMemsize = 0;
+ UINT32 tmp_index = 0;
+ UINT32 Index, j, t;
+ UINT8 checksum = 0;
+
+ if ((NULL == new_interface_mem)
+ || (NULL == MemoryMapPtr))
+ {
+ return ;
+ }
+
+ ZeroMem(reserve_mem, sizeof(MEMMAP) * MAX_MEM_MAP);
+ ZeroMem(free_mem, sizeof(MEMMAP) * MAX_MEM_MAP);
+ ZeroMem(acpi_table_mem, sizeof(MEMMAP) * MAX_MEM_MAP);
+ ZeroMem(acpi_nvs_mem, sizeof(MEMMAP) * MAX_MEM_MAP);
+
+ tmp_index = new_interface_mem->MapCount;
+
+ for (Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++) {
+ if (MemoryMapPtr->NumberOfPages == 0) {
+ continue;
+ }
+
+ switch (MemoryMapPtr->Type) {
+ case EfiACPIReclaimMemory:
+ acpi_table_mem[acpi_table_index].MemType = ACPI_TABLE;
+ acpi_table_mem[acpi_table_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff;
+ acpi_table_mem[acpi_table_index].MemSize = MemoryMapPtr->NumberOfPages * 4096;
+ acpi_table_index++;
+ break;
+
+ case EfiACPIMemoryNVS:
+ acpi_nvs_mem[acpi_nvs_index].MemType = ACPI_NVS;
+ acpi_nvs_mem[acpi_nvs_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff;
+ acpi_nvs_mem[acpi_nvs_index].MemSize = MemoryMapPtr->NumberOfPages * 4096;
+ acpi_nvs_index++;
+ break;
+
+ case EfiRuntimeServicesData:
+ case EfiRuntimeServicesCode:
+ case EfiReservedMemoryType:
+ case EfiPalCode:
+ reserve_mem[reserve_index].MemType = SYSTEM_RAM_RESERVED;
+ reserve_mem[reserve_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff;
+ reserve_mem[reserve_index].MemSize = MemoryMapPtr->NumberOfPages * 4096;
+ reserve_index++;
+ break;
+
+ default :
+ free_mem[free_index].MemType = SYSTEM_RAM;
+ free_mem[free_index].MemStart = (MemoryMapPtr->PhysicalStart) & 0xffffffffffff;
+ free_mem[free_index].MemSize = MemoryMapPtr->NumberOfPages * 4096;
+ free_index++;
+ break;
+ };
+ // Get next item
+ MemoryMapPtr = (EFI_MEMORY_DESCRIPTOR *) ((UINTN)MemoryMapPtr + DescriptorSize);
+ }
+
+ /* Recovery sort */
+ for (j = 0; j < free_index; ) {
+ tempMemsize = free_mem[j].MemSize;
+ for (t = j + 1; t < free_index; t++) {
+ if ((free_mem[j].MemStart + tempMemsize == free_mem[t].MemStart)
+ && (free_mem[j].MemType == free_mem[t].MemType))
+ {
+ tempMemsize += free_mem[t].MemSize;
+ } else {
+ break;
+ }
+ }
+
+ new_interface_mem->Map[tmp_index].MemType = SYSTEM_RAM;
+ new_interface_mem->Map[tmp_index].MemStart = free_mem[j].MemStart;
+ new_interface_mem->Map[tmp_index].MemSize = tempMemsize;
+
+ j = t;
+ tmp_index++;
+ }
+
+ tmp_index = memmap_sort (reserve_mem, reserve_index, new_interface_mem, tmp_index, SYSTEM_RAM_RESERVED);
+
+ new_interface_mem->MapCount = tmp_index;
+ new_interface_mem->Header.CheckSum = 0;
+
+ checksum = CalculateCheckSum8 ((CONST UINT8 *)new_interface_mem, new_interface_mem->Header.Length);
+ new_interface_mem->Header.CheckSum = checksum;
+
+ return ;
+}
+/**
+ Establish linux kernel boot parameters.
+
+ @param Bpi A pointer to the boot parameter interface.
+
+ @retval VOID
+**/
+VOID
+SetupLinuxBootParams (
+ IN OUT BootParamsInterface *Bpi
+ )
+{
+ EFI_MEMORY_DESCRIPTOR *MemoryMapPtr = NULL;
+ MEM_MAP *new_interface_mem = NULL;
+ UINTN MapKey = 0;
+ UINTN MemoryMapSize = 0;
+ UINTN DescriptorSize = 0;
+
+ new_interface_mem = FindNewInterfaceMem (Bpi);
+ MemoryMapPtr = GetSystemMemap (&MapKey, &MemoryMapSize, &DescriptorSize);
+
+ DEBUG ((DEBUG_INFO, "new_interface_mem %p MemoryMapPtr %p MapKey %x.\n",
+ new_interface_mem, MemoryMapPtr, MapKey));
+ MemMapSort (new_interface_mem, MemoryMapPtr, MemoryMapSize, DescriptorSize);
+
+ gBS->ExitBootServices (gImageHandle, MapKey);
+
+ return ;
+}
+
+/**
+ Download the kernel, the initial ramdisk, and the kernel command line from
+ QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+ image files, and load and start the kernel from it.
+
+ The kernel will be instructed via its command line to load the initrd from
+ the same Simple FileSystem.
+
+ @retval EFI_NOT_FOUND Kernel image was not found.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
+
+ @return Error codes from any of the underlying
+ functions. On success, the function doesn't
+ return.
+**/
+EFI_STATUS
+TryRunningQemuKernel (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Size;
+ UINT32 Argc;
+ VOID **Argv;
+ UINTN CommandLineSize;
+ CHAR8 *CommandLine;
+ VOID *KernelEntryPoint;
+ VOID *Bpi;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ CommandLine = NULL;
+ CHAR8 *Args[] = {"a0", CommandLine};
+ Argc = ARRAY_SIZE (Args);
+ Size = Argc * sizeof (VOID **);
+ Size += sizeof (VOID **);
+
+ Size += ALIGN_UP (AsciiStrLen (Args[0]) + 1, 4);
+
+ if (!QemuFwCfgIsAvailable ()) {
+ return EFI_NOT_FOUND;
+ }
+
+ /* get command line size */
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
+ CommandLineSize = (UINTN) QemuFwCfgRead32 ();
+ DEBUG ((DEBUG_INFO, "command line size: %d.\n", CommandLineSize));
+
+ Size += ALIGN_UP (CommandLineSize + 1, 4);
+ DEBUG ((DEBUG_INFO, "kernel args size: %d.\n", Size));
+ //Argv = LoadLinuxAllocateCommandLinePages (EFI_SIZE_TO_PAGES (Size));
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (Size),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Argv = (VOID *) (UINTN) Address;
+ DEBUG ((DEBUG_INFO, "kernel argv address: 0x%0x.\n", Argv));
+
+ VOID **P = Argv;
+ CHAR8 *Pos = (CHAR8 *) (Argv + (Argc + 1));
+ AsciiStrCpyS (Pos, 256, Args[0]);
+ *P++ = Pos;
+
+ Pos += ALIGN_UP (AsciiStrLen (Args[0]) + 1, 4);
+ /* get command line content */
+ QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
+ QemuFwCfgReadBytes (CommandLineSize, Pos);
+ *P++ = Pos;
+
+ *P = NULL;
+
+ /* get kernel entry point */
+ QemuFwCfgSelectItem (QemuFwCfgItemKernelEntry);
+ KernelEntryPoint = (VOID *) ((UINTN) ((UINT32)QemuFwCfgRead64 ()));
+
+ DEBUG ((DEBUG_INFO, "kernel entry point: %p.\n", KernelEntryPoint));
+ if (KernelEntryPoint == NULL) {
+ DEBUG ((DEBUG_INFO, "kernel entry point invalid.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiLoongsonBootparamsTableGuid,
+ (VOID **) &Bpi
+ );
+ if ((EFI_ERROR (Status))
+ || (Bpi == NULL))
+ {
+ DEBUG ((DEBUG_ERROR, "Get Boot Params Table Failed!\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ SetupLinuxBootParams ((BootParamsInterface *)Bpi);
+
+ DEBUG ((DEBUG_INFO, "kernel argc: %d, argv: 0x%0x, bpi: 0x%0x.\n", Argc, Argv, Bpi));
+ DEBUG ((DEBUG_INFO, "entry kernel ...\n"));
+ ((EFI_KERNEL_ENTRY_POINT)KernelEntryPoint) (Argc, Argv, Bpi, NULL);
+
+ return EFI_SUCCESS;
+}
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 14/15] Platform/Loongson: Add Reset System Lib.
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (12 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib xianglai
@ 2022-03-02 8:44 ` xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 15/15] Platform/Loongson: Support Dxe xianglai
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
This library provides interfaces related to restart and shutdown.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Library/ResetSystemLib/ResetSystemLib.c | 155 ++++++++++++++++++
.../Library/ResetSystemLib/ResetSystemLib.inf | 40 +++++
2 files changed, 195 insertions(+)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.c
create mode 100644 Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.c b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.c
new file mode 100644
index 0000000000..3adcb5193a
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.c
@@ -0,0 +1,155 @@
+/** @file
+ Base Reset System Library Shutdown API implementation for LoongArch.
+
+ Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <LoongArchQemuPlatform.h>
+/**
+ To get acpi base address.
+
+ @param VOID
+
+ @retval acpi base address.
+**/
+UINTN
+LoongArchQemuAcpiBase (VOID)
+{
+ VOID *Address = (VOID*) LS7A_ACPI_REG_BASE;
+
+ if (EfiGoneVirtual ()) {
+ /**The RTC controller address and the ResetSystem controller address are in the same page.
+ The function KVMToolRTCMapMemory has placed the entire page address in the memory mapping table,
+ do not add additional.
+ * */
+ EfiConvertPointer (0, &Address);
+ DEBUG ((DEBUG_INFO, "%a: virtual -> 0x%x\n", __FUNCTION__, Address));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: physical -> 0x%x\n", __FUNCTION__, Address));
+ }
+
+ return (UINTN) Address;
+}
+/**
+ Restart device.
+
+ @param VOID
+
+ @retval VOID
+**/
+VOID
+LoongArchQemuReset (VOID)
+{
+
+ UINTN Address;
+
+ DEBUG ((DEBUG_INFO, "%a: LoongArchQemu reset via acpi\n", __FUNCTION__));
+
+ Address = LoongArchQemuAcpiBase ();
+ MmioWrite32 (Address + LS7A_GPE0_RESET_REG, 1);
+ CpuDeadLoop ();
+}
+/**
+ Shutdown device.
+
+ @param VOID
+
+ @retval VOID
+**/
+VOID
+LoongArchQemuShutdown (VOID)
+{
+ UINTN Address;
+
+ //
+ // sleep with S5
+ //
+ Address = LoongArchQemuAcpiBase ();
+ MmioWrite16 (Address + LS7A_PM_CNT_BLK, ACPI_BITMASK_SLEEP_ENABLE);
+ 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)
+{
+ LoongArchQemuReset ();
+}
+
+/**
+ 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)
+{
+ LoongArchQemuReset ();
+}
+
+/**
+ 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
+ )
+{
+ LoongArchQemuReset ();
+}
+
+/**
+ 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 shutdown reset.
+**/
+VOID
+EFIAPI ResetShutdown (VOID)
+{
+ LoongArchQemuShutdown ();
+}
+
+
+/**
+ This function causes the system to enter S3 and then wake up immediately.
+
+ If this function returns, it means that the system does not support S3 feature.
+ **/
+VOID
+EFIAPI
+EnterS3WithImmediateWake (
+ VOID
+ )
+{
+ // not implemented
+}
diff --git a/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf
new file mode 100644
index 0000000000..03bb479d73
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Base Reset System Library Shutdown API implementation for LoongArch.
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ResetSystemLib
+ FILE_GUID = e8579e63-0275-42d6-b52e-0f6d3a8e3369
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = EfiResetSystemLib
+
+
+[Sources.common]
+ ResetSystemLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+
+[LibraryClasses]
+ DebugLib
+ CacheMaintenanceLib
+ MemoryAllocationLib
+ UefiRuntimeServicesTableLib
+ TimerLib
+ UefiLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
+
+[Pcd]
+ gEmbeddedTokenSpaceGuid.PcdFlashFvMainBase
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [edk2-platforms][PATCH V1 15/15] Platform/Loongson: Support Dxe
2022-03-02 8:44 [edk2-platforms][PATCH V1 00/15] Platform: Add Loongson support xianglai
` (13 preceding siblings ...)
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 14/15] Platform/Loongson: Add Reset System Lib xianglai
@ 2022-03-02 8:44 ` xianglai
14 siblings, 0 replies; 16+ messages in thread
From: xianglai @ 2022-03-02 8:44 UTC (permalink / raw)
To: devel
Support Dxe for LoogArch.
Signed-off-by: xianglai li <lixianglai@loongson.cn>
---
.../Loongson/LoongArchQemuPkg/Loongson.dec | 14 +-
.../Loongson/LoongArchQemuPkg/Loongson.dsc | 385 +++++++++++++++++-
.../Loongson/LoongArchQemuPkg/Loongson.fdf | 241 +++++++++++
.../LoongArchQemuPkg/Loongson.fdf.inc | 41 ++
.../LoongArchQemuPkg/VarStore.fdf.inc | 64 +++
5 files changed, 742 insertions(+), 3 deletions(-)
create mode 100644 Platform/Loongson/LoongArchQemuPkg/VarStore.fdf.inc
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
index aca53583f1..508a770a22 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dec
@@ -18,7 +18,8 @@
# Comments are used for Keywords and Module Types.
#
# Supported Module Types:
-# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+# BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+# DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
#
################################################################################
[Includes.common]
@@ -26,12 +27,20 @@
[Guids]
gLoongArchQemuPkgTokenSpaceGuid = { 0x0e0383ce, 0x0151, 0x4d01, { 0x80, 0x0e, 0x3f, 0xef, 0x8b, 0x27, 0x6d, 0x52 } }
+ gEfiLoongsonBootparamsTableGuid = { 0x4660f721, 0x2ec5, 0x416a, { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } }
+
+[Protocols]
[PcdsFixedAtBuild, PcdsDynamic]
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|0x0|UINT64|0x00000003
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize|0x0|UINT32|0x00000004
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvOffset|0x0|UINT64|0x00000007
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|0x0|UINT64|0x00000008
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize|0x0|UINT32|0x00000009
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecModuleBase|0x0|UINT64|0x0000000a
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecModuleSize|0x0|UINT32|0x0000000b
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashEventLogBase|0x0|UINT64|0x0000000c
+ gLoongArchQemuPkgTokenSpaceGuid.PcdFlashEventLogSize|0x0|UINT32|0x0000000d
gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize|0|UINT32|0x00000016
gLoongArchQemuPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|0|UINT32|0x00000017
gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceTreeBase|0x0|UINT64|0x00000018
@@ -47,6 +56,8 @@
[PcdsFixedAtBuild.LOONGARCH64]
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize|0|UINT8|0x00000011
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceSpaceStartAddress|0x10000000|UINT32|0x00000012
+ gLoongArchQemuPkgTokenSpaceGuid.PcdDeviceSpaceLength|0x80000000|UINT32|0x00000013
[PcdsDynamic]
gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize|0x40000000|UINT64|0x00000041
@@ -58,3 +69,4 @@
gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPmd|0x0|UINT64|0x00000047
gLoongArchQemuPkgTokenSpaceGuid.PcdInvalidPte|0x0|UINT64|0x00000048
+[PcdsFeatureFlag]
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
index 09b324c3f7..7d69339674 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.dsc
@@ -24,6 +24,25 @@
FLASH_DEFINITION = Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
TTY_TERMINAL = FALSE
+ #
+ # Defines for default states. These can be changed on the command line.
+ # -D FLAG=VALUE
+ DEFINE TTY_TERMINAL = FALSE
+ DEFINE SECURE_BOOT_ENABLE = FALSE
+ DEFINE TPM2_ENABLE = FALSE
+ DEFINE TPM2_CONFIG_ENABLE = FALSE
+
+ #
+ # Network definition
+ #
+ DEFINE NETWORK_IP6_ENABLE = FALSE
+ DEFINE NETWORK_HTTP_BOOT_ENABLE = FALSE
+ DEFINE NETWORK_SNP_ENABLE = FALSE
+ DEFINE NETWORK_TLS_ENABLE = FALSE
+ DEFINE NETWORK_ALLOW_HTTP_CONNECTIONS = TRUE
+ DEFINE NETWORK_ISCSI_ENABLE = FALSE
+
+!include NetworkPkg/NetworkDefines.dsc.inc
############################################################################
#
# Defines for default states. These can be changed on the command line.
@@ -37,16 +56,25 @@
#
GCC:*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+!include NetworkPkg/NetworkBuildOptions.dsc.inc
[BuildOptions.LOONGARCH64.EDKII.SEC]
*_*_*_CC_FLAGS =
-#[BuildOptions.common.EDKII.DXE_CORE,BuildOptions.common.EDKII.DXE_DRIVER,BuildOptions.common.EDKII.UEFI_DRIVER,BuildOptions.common.EDKII.UEFI_APPLICATION]
-# GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000
+[BuildOptions.common.EDKII.DXE_CORE,BuildOptions.common.EDKII.DXE_DRIVER,BuildOptions.common.EDKII.UEFI_DRIVER,BuildOptions.common.EDKII.UEFI_APPLICATION]
+ GCC:*_*_LOONGARCH64_DLINK_FLAGS = -z common-page-size=0x1000
[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.
@@ -61,19 +89,85 @@
PrintLib | MdePkg/Library/BasePrintLib/BasePrintLib.inf
BaseMemoryLib | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ # Networking Requirements
+!include NetworkPkg/NetworkLibs.dsc.inc
+!if $(NETWORK_TLS_ENABLE) == TRUE
+ TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf
+!endif
BaseLib | MdePkg/Library/BaseLib/BaseLib.inf
+ SafeIntLib | MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+ TimeBaseLib | EmbeddedPkg/Library/TimeBaseLib/TimeBaseLib.inf
+ 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
IoLib | MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
SerialPortLib | Platform/Loongson/LoongArchQemuPkg/Library/SerialPortLib/SerialPortLib.inf
+ EfiResetSystemLib | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf
+ ResetSystemLib | Platform/Loongson/LoongArchQemuPkg/Library/ResetSystemLib/ResetSystemLib.inf
+ UefiLib | MdePkg/Library/UefiLib/UefiLib.inf
+ UefiBootServicesTableLib | MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib | MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiDriverEntryPoint | MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiApplicationEntryPoint | MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ DevicePathLib | MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLibDevicePathProtocol.inf
+ FileHandleLib | MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ SecurityManagementLib | MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
+ UefiUsbLib | MdePkg/Library/UefiUsbLib/UefiUsbLib.inf
+ SerializeVariablesLib | OvmfPkg/Library/SerializeVariablesLib/SerializeVariablesLib.inf
+ CustomizedDisplayLib | MdeModulePkg/Library/CustomizedDisplayLib/CustomizedDisplayLib.inf
DebugPrintErrorLevelLib | MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ TpmMeasurementLib | MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
+ AuthVariableLib | MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf
+ VarCheckLib | MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+ VariablePolicyLib | MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLib.inf
+ VariablePolicyHelperLib | MdeModulePkg/Library/VariablePolicyHelperLib/VariablePolicyHelperLib.inf
+ SortLib | MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
FdtLib | EmbeddedPkg/Library/FdtLib/FdtLib.inf
+ PciPcdProducerLib|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
+ PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+ PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf
+ PciHostBridgeUtilityLib|ArmVirtPkg/Library/ArmVirtPciHostBridgeUtilityLib/ArmVirtPciHostBridgeUtilityLib.inf
+ MmuLib | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLib.inf
+
+!if $(HTTP_BOOT_ENABLE) == TRUE
+ HttpLib | MdeModulePkg/Library/DxeHttpLib/DxeHttpLib.inf
+!endif
+ UefiBootManagerLib | MdeModulePkg/Library/UefiBootManagerLib/UefiBootManagerLib.inf
+ OrderedCollectionLib | MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
+ ReportStatusCodeLib | MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+
+ PeCoffGetEntryPointLib | MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
PeCoffExtraActionLib | MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
DebugAgentLib | MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ CpuExceptionHandlerLib | MdeModulePkg/Library/CpuExceptionHandlerLibNull/CpuExceptionHandlerLibNull.inf
+
+ PlatformBootManagerLib | Platform/Loongson/LoongArchQemuPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+ BootLogoLib | MdeModulePkg/Library/BootLogoLib/BootLogoLib.inf
+ QemuBootOrderLib | OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.inf
+ QemuFwCfgSimpleParserLib | OvmfPkg/Library/QemuFwCfgSimpleParserLib/QemuFwCfgSimpleParserLib.inf
+# QemuLoadImageLib | OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+
+ #
+ # Virtio Support
+ #
+ VirtioLib | OvmfPkg/Library/VirtioLib/VirtioLib.inf
+ FrameBufferBltLib | MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf
+ QemuFwCfgLib | OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.inf
DebugLib | MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
@@ -109,6 +203,50 @@
QemuFwCfgLib | Platform/Loongson/LoongArchQemuPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
MmuLib | Platform/Loongson/LoongArchQemuPkg/Library/MmuLib/MmuBaseLibPei.inf
+[LibraryClasses.common.DXE_CORE]
+ HobLib | MdePkg/Library/DxeCoreHobLib/DxeCoreHobLib.inf
+ DxeCoreEntryPoint | MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+ MemoryAllocationLib | MdeModulePkg/Library/DxeCoreMemoryAllocationLib/DxeCoreMemoryAllocationLib.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ PcdLib | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ HobLib | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ DxeCoreEntryPoint | MdePkg/Library/DxeCoreEntryPoint/DxeCoreEntryPoint.inf
+ MemoryAllocationLib | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+ UefiRuntimeLib | MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ ExtractGuidedSectionLib | MdePkg/Library/PeiExtractGuidedSectionLib/PeiExtractGuidedSectionLib.inf
+ QemuFwCfgS3Lib | OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+ RealTimeClockLib | Platform/Loongson/LoongArchQemuPkg/Library/LsRealTimeClockLib/LsRealTimeClockLib.inf
+ VariablePolicyLib | MdeModulePkg/Library/VariablePolicyLib/VariablePolicyLibRuntimeDxe.inf
+
+[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
+ BpiLib | Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ PcdLib | MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ HobLib | MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib | MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ReportStatusCodeLib | MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+ UefiScsiLib | MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
+ CpuExceptionHandlerLib | UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
+ ExtractGuidedSectionLib | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ QemuFwCfgS3Lib | OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+ BpiLib | Platform/Loongson/LoongArchQemuPkg/Library/BpiLib/BpiLib.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
################################################################################
@@ -116,12 +254,31 @@
# Pcd Section - list of all EDK II PCD Entries defined by this Platform.
#
################################################################################
+[PcdsFeatureFlag]
+# gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial | TRUE
+# gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory | TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSupportUefiDecompress | TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutGopSupport | TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport | FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciBusHotplugDeviceSupport | FALSE
+ gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderPciTranslation | TRUE
+ gUefiOvmfPkgTokenSpaceGuid.PcdQemuBootOrderMmioTranslation | TRUE
[PcdsFixedAtBuild]
## BaseLib ##
gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength | 1000000
gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength | 1000000
gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength | 1000000
+ gEfiMdePkgTokenSpaceGuid.PcdSpinLockTimeout | 10000000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize | 1
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange | FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler | 0x10
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize | 0x2000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize | 0x8000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress | 0x0
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize | 48
+ gEmbeddedTokenSpaceGuid.PcdPrePiCpuIoSize | 32
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask | 0x07
gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel | 0x8000004F
# DEBUG_INIT 0x00000001 // Initialization
# DEBUG_WARN 0x00000002 // Warnings
@@ -168,6 +325,51 @@
# 0x90000000 - 0xA0000000
#
gLoongArchQemuPkgTokenSpaceGuid.PcdUefiRamTop | 0xA0000000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions | 0x04
+
+ #
+ # Network Pcds
+ #
+!include NetworkPkg/NetworkPcds.dsc.inc
+################################################################################
+#
+# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+[PcdsDynamicDefault]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved | 0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration | FALSE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution | 800
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution | 600
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut | 0
+
+ # Set video resolution for text setup.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution | 640
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution | 480
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion | 0x0300
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev | 0x0
+
+ gLoongArchQemuPkgTokenSpaceGuid.PcdRamSize | 0x40000000
+
+ ## If TRUE, OvmfPkg/AcpiPlatformDxe will not wait for PCI
+ # enumeration to complete before installing ACPI tables.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPciDisableBusEnumeration |TRUE
+ gEfiMdePkgTokenSpaceGuid.PcdPciIoTranslation |0x0
+ # set PcdPciExpressBaseAddress to MAX_UINT64, which signifies that this
+ # PCD and PcdPciDisableBusEnumeration above have not been assigned yet
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress |0xFFFFFFFFFFFFFFFF
+
+ #
+ # IPv4 and IPv6 PXE Boot support.
+ #
+ gEfiNetworkPkgTokenSpaceGuid.PcdIPv4PXESupport | 0x01
+ gEfiNetworkPkgTokenSpaceGuid.PcdIPv6PXESupport | 0x01
[Components]
@@ -195,3 +397,182 @@
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
}
+ #
+ # DXE Phase modules
+ #
+ MdeModulePkg/Core/Dxe/DxeMain.inf {
+ <LibraryClasses>
+ NULL | MdeModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ DevicePathLib | MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ ExtractGuidedSectionLib | MdePkg/Library/DxeExtractGuidedSectionLib/DxeExtractGuidedSectionLib.inf
+ }
+
+ MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
+ MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
+ MdeModulePkg/Universal/PCD/Dxe/Pcd.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ }
+
+ MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+ Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
+ MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+ MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+ MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+ MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+ Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
+ MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+ MdeModulePkg/Universal/Metronome/Metronome.inf
+ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+
+ #
+ # Variable
+ #
+# Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
+ OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf {
+ <LibraryClasses>
+ PlatformFvbLib|OvmfPkg/Library/EmuVariableFvbLib/EmuVariableFvbLib.inf
+ }
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
+ <LibraryClasses>
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ }
+
+ #
+ # Platform Driver
+ #
+ OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+ OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+ OvmfPkg/VirtioRngDxe/VirtioRng.inf
+
+ #
+ # File system
+ #
+ MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
+ MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf
+ MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf
+ FatPkg/EnhancedFatDxe/Fat.inf
+
+ #
+ #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/Application/BootManagerMenuApp/BootManagerMenuApp.inf
+ MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+ MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+
+ #
+ # Network Support
+ #
+#!include NetworkPkg/NetworkComponents.dsc.inc
+
+# NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf {
+# <LibraryClasses>
+# NULL|OvmfPkg/Library/PxeBcPcdProducerLib/PxeBcPcdProducerLib.inf
+# }
+
+!if $(NETWORK_TLS_ENABLE) == TRUE
+ NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf {
+ <LibraryClasses>
+ NULL|OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf
+ }
+!endif
+ OvmfPkg/VirtioNetDxe/VirtioNet.inf
+
+
+ #
+ # IDE/SCSI
+ #
+ OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+ MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+ MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+ MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+ #
+ # SMBIOS Support
+ #
+ MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf {
+ <LibraryClasses>
+ NULL | OvmfPkg/Library/SmbiosVersionLib/DetectSmbiosVersionLib.inf
+ }
+ OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+
+ #
+ # PCI
+ #
+ Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+ EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
+ MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+ MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+ OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+ OvmfPkg/Virtio10Dxe/Virtio10.inf
+
+ #
+ # Console
+ #
+ MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+ MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+ MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+ MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
+ MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+ MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+
+ #
+ # Video
+ #
+ OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
+ OvmfPkg/PlatformDxe/Platform.inf
+ OvmfPkg/VirtioGpuDxe/VirtioGpu.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
+ OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf
+
+ #
+ #app
+ #
+ ShellPkg/Application/Shell/Shell.inf {
+ <LibraryClasses>
+ ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
+<PcdsFixedAtBuild>
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+ }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
index f964304fdc..72f8b64394 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf
@@ -22,6 +22,15 @@ $(SECFV_OFFSET)|$(SECFV_SIZE)
gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashSecFvSize
FV = SECFV
+$(PEIFV_OFFSET)|$(PEIFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashPeiFvSize
+FV = PEIFV
+
+$(DXEFV_OFFSET)|$(DXEFV_SIZE)
+gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvBase|gLoongArchQemuPkgTokenSpaceGuid.PcdFlashDxeFvSize
+FV = FVMAIN_COMPACT
+
+!include VarStore.fdf.inc
#####################################################################################################
[FV.SECFV]
FvNameGuid = 587d4265-5e71-41da-9c35-4258551f1e22
@@ -78,6 +87,176 @@ INF MdeModulePkg/Core/Pei/PeiMain.inf
INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
INF Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
+#####################################################################################################
+[FV.DXEFV]
+FvNameGuid = 5d19a5b3-130f-459b-a292-9270a9e6bc62
+BlockSize = $(BLOCK_SIZE)
+FvAlignment = 16
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+
+APRIORI DXE {
+ INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+}
+
+#
+# DXE Phase modules
+#
+INF MdeModulePkg/Core/Dxe/DxeMain.inf
+
+INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
+INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
+INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
+INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf
+INF Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf
+INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
+INF Platform/Loongson/LoongArchQemuPkg/Drivers/StableTimerDxe/TimerDxe.inf
+INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
+INF MdeModulePkg/Universal/Metronome/Metronome.inf
+INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
+INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
+INF EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf
+INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+
+#
+# Variable
+#
+#INF Platform/Loongson/LoongArchQemuPkg/Drivers/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
+INF OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf
+INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+#
+# PCI
+#
+INF Platform/Loongson/LoongArchQemuPkg/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf
+INF EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf
+INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
+INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
+INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
+INF OvmfPkg/Virtio10Dxe/Virtio10.inf
+
+#
+# Platform Driver
+#
+INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
+INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf
+INF OvmfPkg/VirtioRngDxe/VirtioRng.inf
+INF OvmfPkg/VirtioNetDxe/VirtioNet.inf
+
+#
+# Console
+#
+INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
+INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
+INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
+INF MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
+INF MdeModulePkg/Universal/SerialDxe/SerialDxe.inf
+INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf
+
+#
+#Video
+#
+INF OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf
+INF OvmfPkg/PlatformDxe/Platform.inf
+#INF OvmfPkg/VirtioGpuDxe/VirtioGpu.inf
+
+#
+# IDE
+#
+INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf
+INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
+INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf
+INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf
+
+#
+# Usb Support
+#
+INF MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf
+INF MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf
+INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf
+INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf
+INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf
+
+#
+#BDS
+#
+INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
+INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
+INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf
+INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf
+INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
+INF MdeModulePkg/Application/BootManagerMenuApp/BootManagerMenuApp.inf
+
+#
+#Smbios
+#
+INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf
+INF OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf
+
+#
+#Acpi
+#
+INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.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
+
+#
+#Boot OS
+#
+INF ShellPkg/Application/Shell/Shell.inf
+
+#####################################################################################################
+[FV.FVMAIN_COMPACT]
+FvNameGuid = af8c3fe8-9ce8-4548-884a-e3f4dd91f040
+FvAlignment = 16
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 {
+ SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE {
+ SECTION FV_IMAGE = DXEFV
+ }
+ }
#####################################################################################################
[Rule.Common.SEC]
@@ -102,3 +281,65 @@ INF Platform/Loongson/LoongArchQemuPkg/PlatformPei/PlatformPei.inf
}
#####################################################################################################
+[Rule.Common.DXE_CORE]
+ FILE DXE_CORE = $(NAMED_GUID) {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
+[Rule.Common.DXE_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ RAW ACPI Optional |.acpi
+ RAW ASL Optional |.aml
+ }
+
+#####################################################################################################
+[Rule.Common.DXE_RUNTIME_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
+[Rule.Common.UEFI_DRIVER]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
+[Rule.Common.UEFI_DRIVER.BINARY]
+ FILE DRIVER = $(NAMED_GUID) {
+ DXE_DEPEX DXE_DEPEX Optional |.depex
+ PE32 PE32 |.efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
+
+#####################################################################################################
+[Rule.Common.UEFI_APPLICATION]
+ FILE APPLICATION = $(NAMED_GUID) {
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ }
+
+#####################################################################################################
+[Rule.Common.UEFI_APPLICATION.BINARY]
+ FILE APPLICATION = $(NAMED_GUID) {
+ PE32 PE32 |.efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
+
+#####################################################################################################
+[Rule.Common.USER_DEFINED.ACPITABLE]
+ FILE FREEFORM = $(NAMED_GUID) {
+ RAW ACPI |.acpi
+ RAW ASL |.aml
+ }
diff --git a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
index a1a2d537e3..68657bbf4b 100644
--- a/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
+++ b/Platform/Loongson/LoongArchQemuPkg/Loongson.fdf.inc
@@ -19,3 +19,44 @@ DEFINE FD_SIZE = 0x400000
#Set Sec base address and size in flash
DEFINE SECFV_OFFSET = 0x00000000
DEFINE SECFV_SIZE = 0x00010000
+#Set Pei base address and size in flash
+DEFINE PEIFV_OFFSET = 0x00010000
+DEFINE PEIFV_SIZE = 0x00040000
+
+#Set Dxe base address and size in flash
+DEFINE DXEFV_OFFSET = 0x00050000
+DEFINE DXEFV_SIZE = 0x00350000
+
+#Set Var base address and size in flash
+DEFINE VARIABLE_OFFSET = 0x003a0000
+DEFINE VAR_ALL_SIZE = 0x60000
+
+############################################################################
+#Set Var Flash layout
+DEFINE VARIABLE_SIZE = 0x00010000
+DEFINE VAR_ALL_BLOCKS = 0x60
+
+DEFINE RESERVE1_OFFSET = $(VARIABLE_OFFSET) + $(VARIABLE_SIZE)
+DEFINE RESERVE1_SIZE = 0xB000
+
+DEFINE RESERVE2_OFFSET = $(RESERVE1_OFFSET) + $(RESERVE1_SIZE)
+DEFINE RESERVE2_SIZE = 0x14000
+
+DEFINE SPARE_OFFSET = $(RESERVE2_OFFSET) + $(RESERVE2_SIZE)
+DEFINE SPARE_SIZE = 0x20000
+
+DEFINE FWTWORKING_OFFSET = $(SPARE_OFFSET) + $(SPARE_SIZE)
+DEFINE FWTWORKING_SIZE = 0x8000
+
+DEFINE EVENT_LOG_OFFSET = $(FWTWORKING_OFFSET) + $(FWTWORKING_SIZE)
+DEFINE EVENT_LOG_SIZE = 0x8000
+
+# Set Variable
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 = 0
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize = $(VARIABLE_SIZE)
+
+# Set FtwSpare
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize = $(SPARE_SIZE)
+
+# Set FtwWorking
+SET gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize = $(FWTWORKING_SIZE)
diff --git a/Platform/Loongson/LoongArchQemuPkg/VarStore.fdf.inc b/Platform/Loongson/LoongArchQemuPkg/VarStore.fdf.inc
new file mode 100644
index 0000000000..625fa23543
--- /dev/null
+++ b/Platform/Loongson/LoongArchQemuPkg/VarStore.fdf.inc
@@ -0,0 +1,64 @@
+## @file
+#
+# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+$(VARIABLE_OFFSET)|$(VARIABLE_SIZE)
+#NV_VARIABLE_STORE
+DATA = {
+ #jmp to 0x1c060000
+ 0x01, 0x0c, 0x38, 0x14, 0x21, 0x00, 0x80, 0x03,
+ 0x21, 0x00, 0x00, 0x4c, 0x00, 0x10, 0x14, 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: 0x60000
+ 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # Signature "_FVH" # Attributes
+ 0x5f, 0x46, 0x56, 0x48, 0x36, 0x0c, 0x04, 0x00,
+ # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
+ 0x48, 0x00, 0x8F, 0x6B, 0x00, 0x00, 0x00, 0x02,
+ # Blockmap[0]: 0x10 Blocks * 0x1000 Bytes / Block
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ # Blockmap[1]: End
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ## This is the VARIABLE_STORE_HEADER
+ # gEfiVariableGuid = {0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d}}
+ 0x16, 0x36, 0xcf, 0xdd, 0x75, 0x32, 0x64, 0x41,
+ 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d,
+ # Size: 0x10000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
+ # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0xffb8
+ # This can speed up the Variable Dispatch a bit.
+ 0xb8, 0xff, 0x00, 0x00,
+ # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
+ 0x5a, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+$(RESERVE1_OFFSET)|$(RESERVE1_SIZE)
+#NV_RESERVE1_STORE
+
+$(RESERVE2_OFFSET)|$(RESERVE2_SIZE)
+#NV_RESERVE2_STORE
+
+$(SPARE_OFFSET)|$(SPARE_SIZE)
+#NV_FTW_SPARE
+
+$(FWTWORKING_OFFSET)|$(FWTWORKING_SIZE)
+#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
+ 0x07, 0x7f, 0x44, 0x88, 0xfe, 0xff, 0xff, 0xff,
+ # WriteQueueSize: UINT64 #Size:0x8000 - 0x20(FTW_WORKING_HEADER) = 0x7FE0
+ 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+$(EVENT_LOG_OFFSET)|$(EVENT_LOG_SIZE)
+#NV_EVENT_LOG
--
2.27.0
^ permalink raw reply related [flat|nested] 16+ messages in thread