From: "xianglai" <lixianglai@loongson.cn>
To: devel@edk2.groups.io
Subject: [edk2-platforms][PATCH V1 09/15] Platform/Loongson: Add CPU DXE driver.
Date: Wed, 2 Mar 2022 03:44:41 -0500 [thread overview]
Message-ID: <20220302084447.2991355-10-lixianglai@loongson.cn> (raw)
In-Reply-To: <20220302084447.2991355-1-lixianglai@loongson.cn>
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
next prev parent reply other threads:[~2022-03-02 8:45 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` [edk2-platforms][PATCH V1 03/15] Platform/Loongson: Add PeiServicesTablePointerLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 04/15] Platform/Loongson: Add QemuFwCfgLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 05/15] Platform/Loongson: Add BpiLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 06/15] Platform/Loongson: Add MmuLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 07/15] Platform/Loongson: Add StableTimerLib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 08/15] Platform/Loongson: Support PEI phase xianglai
2022-03-02 8:44 ` xianglai [this message]
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 10/15] Platform/Loongson: Add PciCpuIoDxe driver xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 11/15] Platform/Loongson: Add timer Dxe driver xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 12/15] Platform/Loongson: Add RealTime Clock lib xianglai
2022-03-02 8:44 ` [edk2-platforms][PATCH V1 13/15] Platform/Loongson: Add Platform Boot Manager Lib 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220302084447.2991355-10-lixianglai@loongson.cn \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox