<div>Reviewed-by: Chao Li  <lichao@loongson.cn></div><br><div><signature id="local-a67dfd9c-c219"><p style="color:grey;font-size:11px"><br>Thanks,<br>Chao<br>--------<br><br></p></signature></div><div class="gmail_quote_attribution">On 11月 11 2022, at 5:12 δΈ‹εˆ, xianglai li <lixianglai@loongson.cn> wrote:</div><blockquote><div><div>The driver produces EFI_CPU_ARCH_PROTOCOL,</div><br><div>Initialize the exception entry address.</div><br><br><br><div>REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4054</div><br><br><br><div>Cc: Bibo Mao <maobibo@loongson.cn></div><br><div>Cc: Chao Li <lichao@loongson.cn></div><br><div>Cc: Leif Lindholm <quic_llindhol@quicinc.com></div><br><div>Cc: Liming Gao <gaoliming@byosoft.com.cn></div><br><div>Cc: Michael D Kinney <michael.d.kinney@intel.com></div><br><div>Signed-off-by: xianglai li <lixianglai@loongson.cn></div><br><div>---</div><br><div>.../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c | 367 ++++++++++++++++++</div><br><div>.../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h | 199 ++++++++++</div><br><div>.../Drivers/CpuDxe/CpuDxe.inf | 59 +++</div><br><div>.../Drivers/CpuDxe/LoongArch64/Exception.c | 335 ++++++++++++++++</div><br><div>.../Drivers/CpuDxe/LoongArch64/Fpu.S | 97 +++++</div><br><div>.../Drivers/CpuDxe/LoongArch64/LoongArch.S | 321 +++++++++++++++</div><br><div>6 files changed, 1378 insertions(+)</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S</div><br><div>create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S</div><br><br><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c</div><br><div>new file mode 100644</div><br><div>index 0000000000..23f824d82b</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c</div><br><div>@@ -0,0 +1,367 @@</div><br><div>+/** @file</div><br><div>+ CPU DXE Module to produce CPU ARCH Protocol</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+**/</div><br><div>+</div><br><div>+#include <Guid/IdleLoopEvent.h></div><br><div>+#include <Uefi.h></div><br><div>+#include <Library/CacheMaintenanceLib.h></div><br><div>+#include <Library/UefiBootServicesTableLib.h></div><br><div>+#include <Library/CpuLib.h></div><br><div>+#include <Library/DebugLib.h></div><br><div>+#include <Library/BaseLib.h></div><br><div>+#include <Library/MmuLib.h></div><br><div>+#include "CpuDxe.h"</div><br><div>+</div><br><div>+BOOLEAN mInterruptState = FALSE;</div><br><div>+</div><br><div>+/*</div><br><div>+ This function flushes the range of addresses from Start to Start+Length</div><br><div>+ from the processor's data cache. If Start is not aligned to a cache line</div><br><div>+ boundary, then the bytes before Start to the preceding cache line boundary</div><br><div>+ are also flushed. If Start+Length is not aligned to a cache line boundary,</div><br><div>+ then the bytes past Start+Length to the end of the next cache line boundary</div><br><div>+ are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be</div><br><div>+ supported. If the data cache is fully coherent with all DMA operations, then</div><br><div>+ this function can just return EFI_SUCCESS. If the processor does not support</div><br><div>+ flushing a range of the data cache, then the entire data cache can be flushed.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+ @param Start The beginning physical address to flush from the processor's data</div><br><div>+ cache.</div><br><div>+ @param Length The number of bytes to flush from the processor's data cache. This</div><br><div>+ function may flush more bytes than Length specifies depending upon</div><br><div>+ the granularity of the flush operation that the processor supports.</div><br><div>+ @param FlushType Specifies the type of flush operation to perform.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The address range from Start to Start+Length was flushed from</div><br><div>+ the processor's data cache.</div><br><div>+ @retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified</div><br><div>+ by FlushType.</div><br><div>+ @retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed</div><br><div>+ from the processor's data cache.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuFlushCpuDataCache (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN EFI_PHYSICAL_ADDRESS Start,</div><br><div>+ IN UINT64 Length,</div><br><div>+ IN EFI_CPU_FLUSH_TYPE FlushType</div><br><div>+ )</div><br><div>+{</div><br><div>+ switch (FlushType) {</div><br><div>+ case EfiCpuFlushTypeWriteBack:</div><br><div>+ WriteBackDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);</div><br><div>+ break;</div><br><div>+ case EfiCpuFlushTypeInvalidate:</div><br><div>+ InvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);</div><br><div>+ break;</div><br><div>+ case EfiCpuFlushTypeWriteBackInvalidate:</div><br><div>+ WriteBackInvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);</div><br><div>+ break;</div><br><div>+ default:</div><br><div>+ return EFI_INVALID_PARAMETER;</div><br><div>+ }</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function enables interrupt processing by the processor.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS Interrupts are enabled on the processor.</div><br><div>+ @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuEnableInterrupt (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This</div><br><div>+ )</div><br><div>+{</div><br><div>+ EnableInterrupts ();</div><br><div>+</div><br><div>+ mInterruptState = TRUE;</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function disables interrupt processing by the processor.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS Interrupts are disabled on the processor.</div><br><div>+ @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuDisableInterrupt (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This</div><br><div>+ )</div><br><div>+{</div><br><div>+ DisableInterrupts ();</div><br><div>+</div><br><div>+ mInterruptState = FALSE;</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function retrieves the processor's current interrupt state a returns it in</div><br><div>+ State. If interrupts are currently enabled, then TRUE is returned. If interrupts</div><br><div>+ are currently disabled, then FALSE is returned.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+ @param State A pointer to the processor's current interrupt state. Set to TRUE if</div><br><div>+ interrupts are enabled and FALSE if interrupts are disabled.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The processor's current interrupt state was returned in State.</div><br><div>+ @retval EFI_INVALID_PARAMETER State is NULL.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuGetInterruptState (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ OUT BOOLEAN *State</div><br><div>+ )</div><br><div>+{</div><br><div>+ if (State == NULL) {</div><br><div>+ return EFI_INVALID_PARAMETER;</div><br><div>+ }</div><br><div>+</div><br><div>+ *State = mInterruptState;</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function generates an INIT on the processor. If this function succeeds, then the</div><br><div>+ processor will be reset, and control will not be returned to the caller. If InitType is</div><br><div>+ not supported by this processor, or the processor cannot programmatically generate an</div><br><div>+ INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error</div><br><div>+ occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+ @param InitType The type of processor INIT to perform.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.</div><br><div>+ @retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported</div><br><div>+ by this processor.</div><br><div>+ @retval EFI_DEVICE_ERROR The processor INIT failed.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuInit (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN EFI_CPU_INIT_TYPE InitType</div><br><div>+ )</div><br><div>+{</div><br><div>+ return EFI_UNSUPPORTED;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function registers and enables the handler specified by InterruptHandler for a processor</div><br><div>+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the</div><br><div>+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.</div><br><div>+ The installed handler is called once for each processor interrupt or exception.</div><br><div>+</div><br><div>+ @param InterruptType Interrupt Type.</div><br><div>+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called</div><br><div>+ when a processor interrupt occurs. If this parameter is NULL, then the handler</div><br><div>+ will be uninstalled.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.</div><br><div>+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuRegisterInterruptHandler (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN EFI_EXCEPTION_TYPE InterruptType,</div><br><div>+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler</div><br><div>+ )</div><br><div>+{</div><br><div>+ return RegisterInterruptHandler (InterruptType, InterruptHandler);</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Returns a timer value from one of the CPU's internal timers. There is no</div><br><div>+ inherent time interval between ticks but is a function of the CPU frequency.</div><br><div>+</div><br><div>+ @param This - Protocol instance structure.</div><br><div>+ @param TimerIndex - Specifies which CPU timer is requested.</div><br><div>+ @param TimerValue - Pointer to the returned timer value.</div><br><div>+ @param TimerPeriod - A pointer to the amount of time that passes</div><br><div>+ in femtoseconds (10-15) for each increment</div><br><div>+ of TimerValue. If TimerValue does not</div><br><div>+ increment at a predictable rate, then 0 is</div><br><div>+ returned. The amount of time that has</div><br><div>+ passed between two calls to GetTimerValue()</div><br><div>+ can be calculated with the formula</div><br><div>+ (TimerValue2 - TimerValue1) * TimerPeriod.</div><br><div>+ This parameter is optional and may be NULL.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS - If the CPU timer count was returned.</div><br><div>+ @retval EFI_UNSUPPORTED - If the CPU does not have any readable timers.</div><br><div>+ @retval EFI_DEVICE_ERROR - If an error occurred while reading the timer.</div><br><div>+ @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is NULL.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuGetTimerValue (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN UINT32 TimerIndex,</div><br><div>+ OUT UINT64 *TimerValue,</div><br><div>+ OUT UINT64 *TimerPeriod OPTIONAL</div><br><div>+ )</div><br><div>+{</div><br><div>+ return EFI_UNSUPPORTED;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function modifies the attributes for the memory region specified by BaseAddress and</div><br><div>+ Length from their current attributes to the attributes specified by Attributes.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+ @param BaseAddress The physical address that is the start address of a memory region.</div><br><div>+ @param Length The size in bytes of the memory region.</div><br><div>+ @param Attributes The bit mask of attributes to set for the memory region.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The attributes were set for the memory region.</div><br><div>+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by</div><br><div>+ BaseAddress and Length cannot be modified.</div><br><div>+ @retval EFI_INVALID_PARAMETER Length is zero.</div><br><div>+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of</div><br><div>+ the memory resource range.</div><br><div>+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory</div><br><div>+ resource range specified by BaseAddress and Length.</div><br><div>+ The bit mask of attributes is not support for the memory resource</div><br><div>+ range specified by BaseAddress and Length.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuSetMemoryAttributes (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN EFI_PHYSICAL_ADDRESS BaseAddress,</div><br><div>+ IN UINT64 Length,</div><br><div>+ IN UINT64 EfiAttributes</div><br><div>+ )</div><br><div>+{</div><br><div>+ EFI_STATUS Status;</div><br><div>+ UINTN LoongArchAttributes;</div><br><div>+ UINTN RegionBaseAddress;</div><br><div>+ UINTN RegionLength;</div><br><div>+ UINTN RegionLoongArchAttributes;</div><br><div>+</div><br><div>+ if ((BaseAddress & (SIZE_4KB - 1)) != 0) {</div><br><div>+ // Minimum granularity is SIZE_4KB (4KB on ARM)</div><br><div>+ DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_4KB\n",</div><br><div>+ BaseAddress,</div><br><div>+ Length,</div><br><div>+ EfiAttributes));</div><br><div>+</div><br><div>+ return EFI_UNSUPPORTED;</div><br><div>+ }</div><br><div>+ // Convert the 'Attribute' into LoongArch Attribute</div><br><div>+ LoongArchAttributes = EfiAttributeToLoongArchAttribute (EfiAttributes);</div><br><div>+</div><br><div>+ // Get the region starting from 'BaseAddress' and its 'Attribute'</div><br><div>+ RegionBaseAddress = BaseAddress;</div><br><div>+ Status = GetLoongArchMemoryRegion (RegionBaseAddress, BaseAddress + Length,</div><br><div>+ &RegionLength, &RegionLoongArchAttributes);</div><br><div>+</div><br><div>+ LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);</div><br><div>+ // Data & Instruction Caches are flushed when we set new memory attributes.</div><br><div>+ // So, we only set the attributes if the new region is different.</div><br><div>+ if (EFI_ERROR (Status) || (RegionLoongArchAttributes != LoongArchAttributes) ||</div><br><div>+ ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))</div><br><div>+ {</div><br><div>+ return LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);</div><br><div>+ }</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Callback function for idle events.</div><br><div>+</div><br><div>+ @param Event Event whose notification function is being invoked.</div><br><div>+ @param Context The pointer to the notification function's context,</div><br><div>+ which is implementation-dependent.</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+IdleLoopEventCallback (</div><br><div>+ IN EFI_EVENT Event,</div><br><div>+ IN VOID *Context</div><br><div>+ )</div><br><div>+{</div><br><div>+ CpuSleep ();</div><br><div>+}</div><br><div>+</div><br><div>+//</div><br><div>+// Globals used to initialize the protocol</div><br><div>+//</div><br><div>+EFI_HANDLE CpuHandle = NULL;</div><br><div>+EFI_CPU_ARCH_PROTOCOL Cpu = {</div><br><div>+ CpuFlushCpuDataCache,</div><br><div>+ CpuEnableInterrupt,</div><br><div>+ CpuDisableInterrupt,</div><br><div>+ CpuGetInterruptState,</div><br><div>+ CpuInit,</div><br><div>+ CpuRegisterInterruptHandler,</div><br><div>+ CpuGetTimerValue,</div><br><div>+ CpuSetMemoryAttributes,</div><br><div>+ 0, // NumberOfTimers</div><br><div>+ 4, // DmaBufferAlignment</div><br><div>+};</div><br><div>+</div><br><div>+/**</div><br><div>+ Initialize the state information for the CPU Architectural Protocol.</div><br><div>+</div><br><div>+ @param ImageHandle Image handle this driver.</div><br><div>+ @param SystemTable Pointer to the System Table.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS Thread can be successfully created</div><br><div>+ @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure</div><br><div>+ @retval EFI_DEVICE_ERROR Cannot create the thread</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+CpuDxeInitialize (</div><br><div>+ IN EFI_HANDLE ImageHandle,</div><br><div>+ IN EFI_SYSTEM_TABLE *SystemTable</div><br><div>+ )</div><br><div>+{</div><br><div>+ EFI_STATUS Status;</div><br><div>+ EFI_EVENT IdleLoopEvent;</div><br><div>+</div><br><div>+ InitializeExceptions (&Cpu);</div><br><div>+</div><br><div>+ Status = gBS->InstallMultipleProtocolInterfaces (</div><br><div>+ &CpuHandle,</div><br><div>+ &gEfiCpuArchProtocolGuid, &Cpu,</div><br><div>+ NULL</div><br><div>+ );</div><br><div>+</div><br><div>+ //</div><br><div>+ // Setup a callback for idle events</div><br><div>+ //</div><br><div>+ Status = gBS->CreateEventEx (</div><br><div>+ EVT_NOTIFY_SIGNAL,</div><br><div>+ TPL_NOTIFY,</div><br><div>+ IdleLoopEventCallback,</div><br><div>+ NULL,</div><br><div>+ &gIdleLoopEventGuid,</div><br><div>+ &IdleLoopEvent</div><br><div>+ );</div><br><div>+ ASSERT_EFI_ERROR (Status);</div><br><div>+ return Status;</div><br><div>+}</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h</div><br><div>new file mode 100644</div><br><div>index 0000000000..43cb976aa2</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h</div><br><div>@@ -0,0 +1,199 @@</div><br><div>+/** @file</div><br><div>+ CPU DXE Module to produce CPU ARCH Protocol and CPU MP Protocol</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+**/</div><br><div>+</div><br><div>+#ifndef CPU_DXE_H_</div><br><div>+#define CPU_DXE_H_</div><br><div>+</div><br><div>+#include <Protocol/Cpu.h></div><br><div>+</div><br><div>+/**</div><br><div>+ This function registers and enables the handler specified by InterruptHandler for a processor</div><br><div>+ interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the</div><br><div>+ handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.</div><br><div>+ The installed handler is called once for each processor interrupt or exception.</div><br><div>+</div><br><div>+ @param InteruptNum A number of the processor's current interrupt.</div><br><div>+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called</div><br><div>+ when a processor interrupt occurs. If this parameter is NULL, then the handler</div><br><div>+ will be uninstalled.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.</div><br><div>+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InteruptNum was</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is not supported.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+RegisterInterruptHandler (</div><br><div>+ IN EFI_EXCEPTION_TYPE InteruptNum,</div><br><div>+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ This function registers and enables the handler specified by InterruptHandler for a processor</div><br><div>+ interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the</div><br><div>+ handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.</div><br><div>+ The installed handler is called once for each processor interrupt or exception.</div><br><div>+</div><br><div>+ @param InteruptNum A number of the processor's current interrupt.</div><br><div>+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called</div><br><div>+ when a processor interrupt occurs. If this parameter is NULL, then the handler</div><br><div>+ will be uninstalled.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.</div><br><div>+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InteruptNum was</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is not supported.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+RegisterDebuggerInterruptHandler (</div><br><div>+ IN EFI_EXCEPTION_TYPE InteruptNum,</div><br><div>+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler</div><br><div>+ );</div><br><div>+</div><br><div>+/**</div><br><div>+ This function modifies the attributes for the memory region specified by BaseAddress and</div><br><div>+ Length from their current attributes to the attributes specified by Attributes.</div><br><div>+</div><br><div>+ @param This The EFI_CPU_ARCH_PROTOCOL instance.</div><br><div>+ @param BaseAddress The physical address that is the start address of a memory region.</div><br><div>+ @param Length The size in bytes of the memory region.</div><br><div>+ @param Attributes The bit mask of attributes to set for the memory region.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The attributes were set for the memory region.</div><br><div>+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by</div><br><div>+ BaseAddress and Length cannot be modified.</div><br><div>+ @retval EFI_INVALID_PARAMETER Length is zero.</div><br><div>+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of</div><br><div>+ the memory resource range.</div><br><div>+ @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory</div><br><div>+ resource range specified by BaseAddress and Length.</div><br><div>+ The bit mask of attributes is not support for the memory resource</div><br><div>+ range specified by BaseAddress and Length.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+EFIAPI</div><br><div>+CpuSetMemoryAttributes (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *This,</div><br><div>+ IN EFI_PHYSICAL_ADDRESS BaseAddress,</div><br><div>+ IN UINT64 Length,</div><br><div>+ IN UINT64 Attributes</div><br><div>+ );</div><br><div>+</div><br><div>+/** Exception module initialization</div><br><div>+ This function sets the exception base address.</div><br><div>+</div><br><div>+ @param Cpu A pointer to the CPU architecture protocol structure.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS Initialization succeeded</div><br><div>+ @retval EFI_NOT_FOUND Could not Found resources.</div><br><div>+ @retval EFI_OUT_OF_RESOURCES No enough resources.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+InitializeExceptions (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *Cpu</div><br><div>+ );</div><br><div>+</div><br><div>+/** Common exception entry</div><br><div>+ Exception handling is the entry point for the C environment,</div><br><div>+ This function does different things depending on the exception type.</div><br><div>+</div><br><div>+ @param SystemContext The system context at the time of the exception.</div><br><div>+</div><br><div>+ @retval VOID.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+CommonExceptionEntry (</div><br><div>+ IN OUT EFI_SYSTEM_CONTEXT SystemContext</div><br><div>+ );</div><br><div>+</div><br><div>+extern CHAR8 LoongArchException[], LoongArchExceptionEnd[];</div><br><div>+/** Set Exception Base Address</div><br><div>+</div><br><div>+ @param addr Exception Base Address.</div><br><div>+</div><br><div>+ @retval The Old Exception Base Address.</div><br><div>+**/</div><br><div>+extern</div><br><div>+UINT64</div><br><div>+SetEbase (</div><br><div>+ EFI_PHYSICAL_ADDRESS addr</div><br><div>+ );</div><br><div>+/*</div><br><div>+ Load the FPU with signalling NANS. This bit pattern we're using has</div><br><div>+ the property that no matter whether considered as single or as double</div><br><div>+ precision represents signaling NANS.</div><br><div>+</div><br><div>+ @param fcsr The value to initialize FCSR0</div><br><div>+</div><br><div>+ @retval The Old Exception Base Address.</div><br><div>+ */</div><br><div>+extern</div><br><div>+VOID</div><br><div>+InitFpu (</div><br><div>+ UINT32 fcsr</div><br><div>+ );</div><br><div>+</div><br><div>+/*</div><br><div>+ Read Csr EUEN register.</div><br><div>+</div><br><div>+ @param CsrEuen Pointer to the variable used to store the EUEN register value</div><br><div>+</div><br><div>+ @retval none</div><br><div>+ */</div><br><div>+extern</div><br><div>+VOID</div><br><div>+LoongArchReadqCsrEuen (</div><br><div>+ UINT64 *CsrEuen</div><br><div>+ );</div><br><div>+</div><br><div>+/*</div><br><div>+ Write Csr EUEN register.</div><br><div>+</div><br><div>+ @param The value used to write to the EUEN register</div><br><div>+</div><br><div>+ @retval none</div><br><div>+ */</div><br><div>+extern</div><br><div>+VOID</div><br><div>+LoongArchWriteqCsrEuen (</div><br><div>+ UINT64 CsrEuen</div><br><div>+ );</div><br><div>+</div><br><div>+/*</div><br><div>+ Enables floating-point unit</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+</div><br><div>+ @retval VOID</div><br><div>+ */</div><br><div>+extern</div><br><div>+VOID</div><br><div>+LoongArchEnableFpu (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+/*</div><br><div>+ Disable floating-point unit</div><br><div>+</div><br><div>+ @param VOID</div><br><div>+</div><br><div>+ @retval VOID</div><br><div>+ */</div><br><div>+extern</div><br><div>+VOID</div><br><div>+LoongArchDisableFpu (</div><br><div>+ VOID</div><br><div>+ );</div><br><div>+</div><br><div>+#endif // CPU_DXE_H_</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf</div><br><div>new file mode 100644</div><br><div>index 0000000000..96aabfefb8</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.inf</div><br><div>@@ -0,0 +1,59 @@</div><br><div>+## @file</div><br><div>+# CPU driver installs CPU Architecture Protocol and CPU MP protocol.</div><br><div>+#</div><br><div>+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+#</div><br><div>+# SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+#</div><br><div>+##</div><br><div>+</div><br><div>+[Defines]</div><br><div>+ INF_VERSION = 0x00010005</div><br><div>+ BASE_NAME = CpuDxe</div><br><div>+ FILE_GUID = bf954921-25c1-48c0-9bfb-8d0cd7ee92da</div><br><div>+ MODULE_TYPE = DXE_DRIVER</div><br><div>+ VERSION_STRING = 1.0</div><br><div>+ ENTRY_POINT = CpuDxeInitialize</div><br><div>+</div><br><div>+#</div><br><div>+# VALID_ARCHITECTURES = LOONGARCH64</div><br><div>+#</div><br><div>+</div><br><div>+[Sources.Common]</div><br><div>+ CpuDxe.c</div><br><div>+ CpuDxe.h</div><br><div>+</div><br><div>+[Sources.LOONGARCH64]</div><br><div>+ LoongArch64/Exception.c</div><br><div>+ LoongArch64/LoongArch.S</div><br><div>+ LoongArch64/Fpu.S</div><br><div>+</div><br><div>+[Packages]</div><br><div>+ MdePkg/MdePkg.dec</div><br><div>+ MdeModulePkg/MdeModulePkg.dec</div><br><div>+ EmbeddedPkg/EmbeddedPkg.dec</div><br><div>+ Platform/Loongson/LoongArchQemuPkg/Loongson.dec</div><br><div>+</div><br><div>+[LibraryClasses]</div><br><div>+ BaseLib</div><br><div>+ BaseMemoryLib</div><br><div>+ CacheMaintenanceLib</div><br><div>+ CpuLib</div><br><div>+ DebugLib</div><br><div>+ DxeServicesTableLib</div><br><div>+ HobLib</div><br><div>+ PeCoffGetEntryPointLib</div><br><div>+ UefiDriverEntryPoint</div><br><div>+ UefiLib</div><br><div>+ MmuLib</div><br><div>+</div><br><div>+[Protocols]</div><br><div>+ gEfiCpuArchProtocolGuid</div><br><div>+ gEfiMpServiceProtocolGuid</div><br><div>+</div><br><div>+[Guids]</div><br><div>+ gEfiDebugImageInfoTableGuid</div><br><div>+ gIdleLoopEventGuid</div><br><div>+</div><br><div>+[Depex]</div><br><div>+ TRUE</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c</div><br><div>new file mode 100644</div><br><div>index 0000000000..793ae90e4f</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Exception.c</div><br><div>@@ -0,0 +1,335 @@</div><br><div>+/** @file</div><br><div>+</div><br><div>+ Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+</div><br><div>+ SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+</div><br><div>+ @par Glossary:</div><br><div>+ - ESTAT - Exception Status</div><br><div>+ - ECFG - Exception Configure</div><br><div>+ - ERA - Exception Return Address</div><br><div>+ - BADV - Bad Virtual Address</div><br><div>+ - BADI - Bad Instructions</div><br><div>+ - Epc or EPC or epc - Exception Program Counter</div><br><div>+ - pc or PC or pc - Program Counter</div><br><div>+ - CRMD - Current Mode</div><br><div>+ - PRMD - Previous Mode</div><br><div>+ - CsrEuen - Cpu Status Register Extern Unit Enable</div><br><div>+ - fpu or fp or FP - Float Point Unit</div><br><div>+ - LOONGARCH - Loongson Arch</div><br><div>+ - Irq - Interrupt ReQuest</div><br><div>+**/</div><br><div>+</div><br><div>+#include "Library/Cpu.h"</div><br><div>+#include <Library/BaseMemoryLib.h></div><br><div>+#include <Library/UefiBootServicesTableLib.h></div><br><div>+#include <Library/UefiLib.h></div><br><div>+#include <Library/CacheMaintenanceLib.h></div><br><div>+#include <Library/DebugLib.h></div><br><div>+#include "CpuDxe.h"</div><br><div>+#include <Library/PeCoffGetEntryPointLib.h></div><br><div>+#include <Library/UefiLib.h></div><br><div>+#include <Guid/DebugImageInfoTable.h></div><br><div>+</div><br><div>+EFI_EXCEPTION_CALLBACK gInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1];</div><br><div>+EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_LOONGARCH_INTERRUPT + 1];</div><br><div>+</div><br><div>+/**</div><br><div>+ This function registers and enables the handler specified by InterruptHandler for a processor</div><br><div>+ interrupt or exception type specified by InteruptNum. If InterruptHandler is NULL, then the</div><br><div>+ handler for the processor interrupt or exception type specified by InteruptNum is uninstalled.</div><br><div>+ The installed handler is called once for each processor interrupt or exception.</div><br><div>+</div><br><div>+ @param InteruptNum A number of the processor's current interrupt.</div><br><div>+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called</div><br><div>+ when a processor interrupt occurs. If this parameter is NULL, then the handler</div><br><div>+ will be uninstalled.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.</div><br><div>+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InteruptNum was</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InteruptNum was not</div><br><div>+ previously installed.</div><br><div>+ @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is not supported.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+RegisterInterruptHandler (</div><br><div>+ IN EFI_EXCEPTION_TYPE InteruptNum,</div><br><div>+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler</div><br><div>+ )</div><br><div>+{</div><br><div>+ if (InteruptNum > MAX_LOONGARCH_INTERRUPT) {</div><br><div>+ return EFI_UNSUPPORTED;</div><br><div>+ }</div><br><div>+</div><br><div>+ if ((InterruptHandler != NULL)</div><br><div>+ && (gInterruptHandler[InteruptNum] != NULL))</div><br><div>+ {</div><br><div>+ return EFI_ALREADY_STARTED;</div><br><div>+ }</div><br><div>+</div><br><div>+ gInterruptHandler[InteruptNum] = InterruptHandler;</div><br><div>+</div><br><div>+ return EFI_SUCCESS;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ This function calls the corresponding exception handler based on the exception type.</div><br><div>+</div><br><div>+ @param SystemContext The system context at the time of the exception.</div><br><div>+</div><br><div>+ @retval VOID</div><br><div>+**/</div><br><div>+STATIC VOID</div><br><div>+EFIAPI</div><br><div>+CommonInterruptHandler (</div><br><div>+ IN OUT EFI_SYSTEM_CONTEXT SystemContext</div><br><div>+ )</div><br><div>+{</div><br><div>+ INT32 Pending;</div><br><div>+ INT32 InterruptNum;</div><br><div>+ /*Interrupt [13-0] NMI IPI TI PCOV hw IP10-IP2 soft IP1-IP0*/</div><br><div>+ Pending = ((SystemContext.SystemContextLoongArch64->ESTAT) &</div><br><div>+ (SystemContext.SystemContextLoongArch64->ECFG) & 0x1fff);</div><br><div>+ for (InterruptNum = 0; InterruptNum < MAX_LOONGARCH_INTERRUPT; InterruptNum++) {</div><br><div>+ if (Pending & (1 << InterruptNum)) {</div><br><div>+ if (gInterruptHandler[InterruptNum] != NULL) {</div><br><div>+ gInterruptHandler[InterruptNum] (InterruptNum, SystemContext);</div><br><div>+ } else {</div><br><div>+ DEBUG ((DEBUG_INFO, "Pending: 0x%0x, InterruptNum: 0x%0x\n", Pending, InterruptNum));</div><br><div>+ }</div><br><div>+ }</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ Use the EFI Debug Image Table to lookup the FaultAddress and find which PE/COFF image</div><br><div>+ it came from. As long as the PE/COFF image contains a debug directory entry a</div><br><div>+ string can be returned. For ELF and Mach-O images the string points to the Mach-O or ELF</div><br><div>+ image. Microsoft tools contain a pointer to the PDB file that contains the debug information.</div><br><div>+</div><br><div>+ @param FaultAddress Address to find PE/COFF image for.</div><br><div>+ @param ImageBase Return load address of found image</div><br><div>+ @param PeCoffSizeOfHeaders Return the size of the PE/COFF header for the image that was found</div><br><div>+</div><br><div>+ @retval NULL FaultAddress not in a loaded PE/COFF image.</div><br><div>+ @retval Path and file name of PE/COFF image.</div><br><div>+**/</div><br><div>+CHAR8 *</div><br><div>+GetImageName (</div><br><div>+ IN UINTN FaultAddress,</div><br><div>+ OUT UINTN *ImageBase,</div><br><div>+ OUT UINTN *PeCoffSizeOfHeaders</div><br><div>+ )</div><br><div>+{</div><br><div>+ EFI_STATUS Status;</div><br><div>+ EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugTableHeader;</div><br><div>+ EFI_DEBUG_IMAGE_INFO *DebugTable;</div><br><div>+ UINTN Entry;</div><br><div>+ CHAR8 *Address;</div><br><div>+</div><br><div>+ Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&DebugTableHeader);</div><br><div>+ if (EFI_ERROR (Status)) {</div><br><div>+ return NULL;</div><br><div>+ }</div><br><div>+</div><br><div>+ DebugTable = DebugTableHeader->EfiDebugImageInfoTable;</div><br><div>+ if (DebugTable == NULL) {</div><br><div>+ return NULL;</div><br><div>+ }</div><br><div>+</div><br><div>+ Address = (CHAR8 *)(UINTN)FaultAddress;</div><br><div>+ for (Entry = 0; Entry < DebugTableHeader->TableSize; Entry++, DebugTable++) {</div><br><div>+ if (DebugTable->NormalImage != NULL) {</div><br><div>+ if ((DebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&</div><br><div>+ (DebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {</div><br><div>+ if ((Address >= (CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase) &&</div><br><div>+ (Address <= ((CHAR8 *)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolInstance->ImageSize))) {</div><br><div>+ *ImageBase = (UINTN)DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase;</div><br><div>+ *PeCoffSizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)*ImageBase);</div><br><div>+ return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase);</div><br><div>+ }</div><br><div>+ }</div><br><div>+ }</div><br><div>+ }</div><br><div>+ return NULL;</div><br><div>+}</div><br><div>+</div><br><div>+/**</div><br><div>+ pass a file name string that contains the path, return file name.</div><br><div>+</div><br><div>+ @param FullName Path and file name</div><br><div>+</div><br><div>+ @retval file name.</div><br><div>+**/</div><br><div>+STATIC</div><br><div>+CONST CHAR8 *</div><br><div>+BaseName (</div><br><div>+ IN CONST CHAR8 *FullName</div><br><div>+ )</div><br><div>+{</div><br><div>+ CONST CHAR8 *Str;</div><br><div>+</div><br><div>+ Str = FullName + AsciiStrLen (FullName);</div><br><div>+</div><br><div>+ while (--Str > FullName) {</div><br><div>+ if (*Str == '/' || *Str == '\\') {</div><br><div>+ return Str + 1;</div><br><div>+ }</div><br><div>+ }</div><br><div>+ return Str;</div><br><div>+}</div><br><div>+</div><br><div>+/** Default Exception Handler Function</div><br><div>+ This function is called when an exception occurs that cannot be handled,</div><br><div>+ and this function prints the system context information when the interrupt occurred</div><br><div>+</div><br><div>+ @param SystemContext The system context at the time of the exception.</div><br><div>+</div><br><div>+ @retval VOID.</div><br><div>+**/</div><br><div>+STATIC</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+DefaultHandler (</div><br><div>+ IN OUT EFI_SYSTEM_CONTEXT SystemContext</div><br><div>+ )</div><br><div>+{</div><br><div>+ CHAR8 *ImageName;</div><br><div>+ UINTN ImageBase;</div><br><div>+ UINTN Epc;</div><br><div>+ UINTN PeCoffSizeOfHeader;</div><br><div>+</div><br><div>+ DEBUG ((DEBUG_ERROR, "CRMD 0x%llx\n", SystemContext.SystemContextLoongArch64->CRMD));</div><br><div>+ DEBUG ((DEBUG_ERROR, "PRMD 0x%llx\n", SystemContext.SystemContextLoongArch64->PRMD));</div><br><div>+ DEBUG ((DEBUG_ERROR, "ECFG 0x%llx\n", SystemContext.SystemContextLoongArch64->ECFG));</div><br><div>+ DEBUG ((DEBUG_ERROR, "ESTAT 0x%llx\n", SystemContext.SystemContextLoongArch64->ESTAT));</div><br><div>+ DEBUG ((DEBUG_ERROR, "ERA 0x%llx\n", SystemContext.SystemContextLoongArch64->ERA));</div><br><div>+ DEBUG ((DEBUG_ERROR, "BADV 0x%llx\n", SystemContext.SystemContextLoongArch64->BADV));</div><br><div>+ DEBUG ((DEBUG_ERROR, "BADI 0x%llx\n", SystemContext.SystemContextLoongArch64->BADI));</div><br><div>+</div><br><div>+ Epc = SystemContext.SystemContextLoongArch64->ERA;</div><br><div>+ ImageName = GetImageName (Epc, &ImageBase, &PeCoffSizeOfHeader);</div><br><div>+ if (ImageName != NULL) {</div><br><div>+ DEBUG ((DEBUG_ERROR, "PC 0x%012lx (0x%012lx+0x%08x) [ 0] %a\n",</div><br><div>+ Epc, ImageBase,</div><br><div>+ Epc - ImageBase, BaseName (ImageName)));</div><br><div>+ } else {</div><br><div>+ DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Epc));</div><br><div>+ }</div><br><div>+</div><br><div>+ while (1);</div><br><div>+}</div><br><div>+</div><br><div>+/** Common exception entry</div><br><div>+ Exception handling is the entry point for the C environment,</div><br><div>+ This function does different things depending on the exception type.</div><br><div>+</div><br><div>+ @param SystemContext The system context at the time of the exception.</div><br><div>+</div><br><div>+ @retval VOID.</div><br><div>+**/</div><br><div>+VOID</div><br><div>+EFIAPI</div><br><div>+CommonExceptionEntry (</div><br><div>+ IN OUT EFI_SYSTEM_CONTEXT SystemContext</div><br><div>+ )</div><br><div>+{</div><br><div>+ INT32 ExceptionType;</div><br><div>+ UINT64 CsrEuen;</div><br><div>+ UINT64 FpuStatus;</div><br><div>+</div><br><div>+ ExceptionType = SystemContext.SystemContextLoongArch64->ESTAT & CSR_ESTAT_EXC;</div><br><div>+ ExceptionType = ExceptionType >> CSR_ESTAT_EXC_SHIFT;</div><br><div>+</div><br><div>+ LoongArchReadqCsrEuen (&CsrEuen);</div><br><div>+ FpuStatus = CsrEuen & CSR_EUEN_FPEN;</div><br><div>+ switch (ExceptionType) {</div><br><div>+ case EXC_INT:</div><br><div>+ /*</div><br><div>+ * handle interrupt exception</div><br><div>+ */</div><br><div>+ CommonInterruptHandler (SystemContext);</div><br><div>+ if (!FpuStatus) {</div><br><div>+ LoongArchReadqCsrEuen (&CsrEuen);</div><br><div>+ if (CsrEuen & CSR_EUEN_FPEN) {</div><br><div>+ /*</div><br><div>+ * Since Hw FP is enabled during interrupt handler,</div><br><div>+ * disable FP</div><br><div>+ */</div><br><div>+ CsrEuen &= ~CSR_EUEN_FPEN;</div><br><div>+ LoongArchWriteqCsrEuen (CsrEuen);</div><br><div>+ }</div><br><div>+ }</div><br><div>+ break;</div><br><div>+ case EXC_FPDIS:</div><br><div>+ /*</div><br><div>+ * Hardware FP disabled exception,</div><br><div>+ * Enable and init FP registers here</div><br><div>+ */</div><br><div>+ LoongArchEnableFpu ();</div><br><div>+ InitFpu(FPU_CSR_RN);</div><br><div>+ break;</div><br><div>+ default:</div><br><div>+ DefaultHandler(SystemContext);</div><br><div>+ break;</div><br><div>+ }</div><br><div>+}</div><br><div>+</div><br><div>+/** Exception module initialization</div><br><div>+ This function sets the exception base address.</div><br><div>+</div><br><div>+ @param Cpu A pointer to the CPU architecture protocol structure.</div><br><div>+</div><br><div>+ @retval EFI_SUCCESS Initialization succeeded</div><br><div>+ @retval EFI_NOT_FOUND Could not Found resources.</div><br><div>+ @retval EFI_OUT_OF_RESOURCES No enough resources.</div><br><div>+**/</div><br><div>+EFI_STATUS</div><br><div>+InitializeExceptions (</div><br><div>+ IN EFI_CPU_ARCH_PROTOCOL *Cpu</div><br><div>+ )</div><br><div>+{</div><br><div>+ EFI_STATUS Status;</div><br><div>+ BOOLEAN IrqEnabled;</div><br><div>+ EFI_PHYSICAL_ADDRESS Address;</div><br><div>+</div><br><div>+ ZeroMem (gInterruptHandler, sizeof (*gInterruptHandler));</div><br><div>+</div><br><div>+ //</div><br><div>+ // Disable interrupts</div><br><div>+ //</div><br><div>+ Cpu->GetInterruptState (Cpu, &IrqEnabled);</div><br><div>+ Cpu->DisableInterrupt (Cpu);</div><br><div>+</div><br><div>+ //</div><br><div>+ // EFI does not use the FIQ, but a debugger might so we must disable</div><br><div>+ // as we take over the exception vectors.</div><br><div>+ //</div><br><div>+ Status = gBS->AllocatePages (</div><br><div>+ AllocateAnyPages,</div><br><div>+ EfiRuntimeServicesData,</div><br><div>+ 1,</div><br><div>+ &Address</div><br><div>+ );</div><br><div>+ if (EFI_ERROR (Status)) {</div><br><div>+ return Status;</div><br><div>+ }</div><br><div>+</div><br><div>+ DEBUG ((DEBUG_INFO, "Set Exception Base Address\n"));</div><br><div>+ CopyMem ((char *)Address, LoongArchException, (LoongArchExceptionEnd - LoongArchException));</div><br><div>+ InvalidateInstructionCacheRange ((char *)Address, (LoongArchExceptionEnd - LoongArchException));</div><br><div>+</div><br><div>+ SetEbase (Address);</div><br><div>+ DEBUG ((DEBUG_INFO, "LoongArchException address: 0x%p\n", Address));</div><br><div>+ DEBUG ((DEBUG_INFO, "LoongArchExceptionEnd address: 0x%p\n", Address + (LoongArchExceptionEnd - LoongArchException)));</div><br><div>+</div><br><div>+ DEBUG ((DEBUG_INFO, "InitializeExceptions, IrqEnabled = %x\n", IrqEnabled));</div><br><div>+ if (IrqEnabled) {</div><br><div>+ //</div><br><div>+ // Restore interrupt state</div><br><div>+ //</div><br><div>+ Status = Cpu->EnableInterrupt (Cpu);</div><br><div>+ }</div><br><div>+ return Status;</div><br><div>+}</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S</div><br><div>new file mode 100644</div><br><div>index 0000000000..79a20c66a2</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Fpu.S</div><br><div>@@ -0,0 +1,97 @@</div><br><div>+#------------------------------------------------------------------------------</div><br><div>+#</div><br><div>+# Fpu for LoongArch</div><br><div>+#</div><br><div>+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+#</div><br><div>+# SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+#</div><br><div>+# @par Glossary:</div><br><div>+# - CsrEuen - Cpu Status Register Extern Unit Enable</div><br><div>+# - FPEN - FPU Enable</div><br><div>+# - fpu or fp or FP - Float Point Unit</div><br><div>+#-----------------------------------------------------------------------------</div><br><div>+#ifndef __ASSEMBLY__</div><br><div>+#define __ASSEMBLY__</div><br><div>+#endif</div><br><div>+#include "Library/Cpu.h"</div><br><div>+#include "CpuDxe.h"</div><br><div>+</div><br><div>+ASM_GLOBAL ASM_PFX(InitFpu)</div><br><div>+ASM_GLOBAL ASM_PFX(LoongArchEnableFpu)</div><br><div>+ASM_GLOBAL ASM_PFX(LoongArchDisableFpu)</div><br><div>+</div><br><div>+#</div><br><div>+# Load the FPU with signalling NANS. This bit pattern we're using has</div><br><div>+# the property that no matter whether considered as single or as double</div><br><div>+# precision represents signaling NANS.</div><br><div>+#</div><br><div>+# The value to initialize FCSR0 to comes in $A0.</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(InitFpu):</div><br><div>+ li.d T1, CSR_EUEN_FPEN</div><br><div>+ csrxchg T1, T1, LOONGARCH_CSR_EUEN</div><br><div>+</div><br><div>+ movgr2fcsr FCSR0, A0</div><br><div>+ li.d T1, -1 # SNaN</div><br><div>+ movgr2fr.d $f0, T1</div><br><div>+ movgr2fr.d $f1, T1</div><br><div>+ movgr2fr.d $f2, T1</div><br><div>+ movgr2fr.d $f3, T1</div><br><div>+ movgr2fr.d $f4, T1</div><br><div>+ movgr2fr.d $f5, T1</div><br><div>+ movgr2fr.d $f6, T1</div><br><div>+ movgr2fr.d $f7, T1</div><br><div>+ movgr2fr.d $f8, T1</div><br><div>+ movgr2fr.d $f9, T1</div><br><div>+ movgr2fr.d $f10, T1</div><br><div>+ movgr2fr.d $f11, T1</div><br><div>+ movgr2fr.d $f12, T1</div><br><div>+ movgr2fr.d $f13, T1</div><br><div>+ movgr2fr.d $f14, T1</div><br><div>+ movgr2fr.d $f15, T1</div><br><div>+ movgr2fr.d $f16, T1</div><br><div>+ movgr2fr.d $f17, T1</div><br><div>+ movgr2fr.d $f18, T1</div><br><div>+ movgr2fr.d $f19, T1</div><br><div>+ movgr2fr.d $f20, T1</div><br><div>+ movgr2fr.d $f21, T1</div><br><div>+ movgr2fr.d $f22, T1</div><br><div>+ movgr2fr.d $f23, T1</div><br><div>+ movgr2fr.d $f24, T1</div><br><div>+ movgr2fr.d $f25, T1</div><br><div>+ movgr2fr.d $f26, T1</div><br><div>+ movgr2fr.d $f27, T1</div><br><div>+ movgr2fr.d $f28, T1</div><br><div>+ movgr2fr.d $f29, T1</div><br><div>+ movgr2fr.d $f30, T1</div><br><div>+ movgr2fr.d $f31, T1</div><br><div>+</div><br><div>+ jirl ZERO, RA, 0</div><br><div>+</div><br><div>+#</div><br><div>+# Enables floating-point unit</div><br><div>+# @param VOID</div><br><div>+# @retval VOID</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(LoongArchEnableFpu):</div><br><div>+ li.d T0, 1</div><br><div>+ li.d T1, CSR_EUEN_FPEN_SHIFT</div><br><div>+ sll.d T0, T0, T1</div><br><div>+ csrxchg T0, T0, LOONGARCH_CSR_EUEN</div><br><div>+ jirl ZERO, RA,0</div><br><div>+</div><br><div>+#</div><br><div>+# Disable floating-point unit</div><br><div>+# @param VOID</div><br><div>+# @retval VOID</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(LoongArchDisableFpu):</div><br><div>+ li.d T0, 1</div><br><div>+ li.d T1, CSR_EUEN_FPEN_SHIFT</div><br><div>+ sll.d T0, T0, T1</div><br><div>+ csrxchg ZERO, T0, LOONGARCH_CSR_EUEN</div><br><div>+ jirl ZERO, RA,0</div><br><div>diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S</div><br><div>new file mode 100644</div><br><div>index 0000000000..e463cf44f2</div><br><div>--- /dev/null</div><br><div>+++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongArch.S</div><br><div>@@ -0,0 +1,321 @@</div><br><div>+#------------------------------------------------------------------------------</div><br><div>+#</div><br><div>+# LoongArch for LoongArch</div><br><div>+#</div><br><div>+# Copyright (c) 2022 Loongson Technology Corporation Limited. All rights reserved.<BR></div><br><div>+#</div><br><div>+# SPDX-License-Identifier: BSD-2-Clause-Patent</div><br><div>+#</div><br><div>+# @par Glossary:</div><br><div>+# - CsrEuen - Cpu Status Register Extern Unit Enable</div><br><div>+# - fpu - Float Point Unit</div><br><div>+# - LOONGARCH - Loongson Arch</div><br><div>+# - Ebase - Exception Base Address</div><br><div>+#-----------------------------------------------------------------------------</div><br><div>+</div><br><div>+#ifndef __ASSEMBLY__</div><br><div>+#define __ASSEMBLY__</div><br><div>+#endif</div><br><div>+</div><br><div>+#include "Library/Cpu.h"</div><br><div>+#include "CpuDxe.h"</div><br><div>+</div><br><div>+#define RSIZE 8 /* 64 bit mode register size */</div><br><div>+#define RLOGSIZE 3</div><br><div>+</div><br><div>+ASM_GLOBAL ASM_PFX(Exception_handler)</div><br><div>+ASM_GLOBAL ASM_PFX(LoongArchException)</div><br><div>+ASM_GLOBAL ASM_PFX(SetEbase)</div><br><div>+ASM_GLOBAL ASM_PFX(LoongArchReadqCsrEuen)</div><br><div>+ASM_GLOBAL ASM_PFX(LoongArchWriteqCsrEuen)</div><br><div>+</div><br><div>+#</div><br><div>+# Main exception handler. Not really a leaf routine but not a normal</div><br><div>+# function either. Save away the entire cpu state end enter exception mode.</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(Exception_handler):</div><br><div>+ csrrd SP, LOONGARCH_CSR_KS1</div><br><div>+</div><br><div>+ addi.d T0, $r0, -0x10</div><br><div>+ and SP, SP, T0</div><br><div>+ addi.d SP, SP, -((CSR_NUM + BASE_NUM + FP_BASE_NUM) * RSIZE)</div><br><div>+</div><br><div>+ st.d RA, SP, RA_NUM * RSIZE</div><br><div>+ st.d GP, SP, GP_NUM * RSIZE</div><br><div>+ st.d A0, SP, A0_NUM * RSIZE</div><br><div>+ st.d A1, SP, A1_NUM * RSIZE</div><br><div>+ st.d A2, SP, A2_NUM * RSIZE</div><br><div>+ st.d A3, SP, A3_NUM * RSIZE</div><br><div>+ st.d A4, SP, A4_NUM * RSIZE</div><br><div>+ st.d A5, SP, A5_NUM * RSIZE</div><br><div>+ st.d A6, SP, A6_NUM * RSIZE</div><br><div>+ st.d A7, SP, A7_NUM * RSIZE</div><br><div>+ st.d T1, SP, T1_NUM * RSIZE</div><br><div>+ st.d T2, SP, T2_NUM * RSIZE</div><br><div>+ st.d T3, SP, T3_NUM * RSIZE</div><br><div>+ st.d T4, SP, T4_NUM * RSIZE</div><br><div>+ st.d T5, SP, T5_NUM * RSIZE</div><br><div>+ st.d T6, SP, T6_NUM * RSIZE</div><br><div>+ st.d T7, SP, T7_NUM * RSIZE</div><br><div>+ st.d T8, SP, T8_NUM * RSIZE</div><br><div>+ st.d TP, SP, TP_NUM * RSIZE</div><br><div>+ st.d FP, SP, FP_NUM * RSIZE</div><br><div>+ st.d S0, SP, S0_NUM * RSIZE</div><br><div>+ st.d S1, SP, S1_NUM * RSIZE</div><br><div>+ st.d S2, SP, S2_NUM * RSIZE</div><br><div>+ st.d S3, SP, S3_NUM * RSIZE</div><br><div>+ st.d S4, SP, S4_NUM * RSIZE</div><br><div>+ st.d S5, SP, S5_NUM * RSIZE</div><br><div>+ st.d S6, SP, S6_NUM * RSIZE</div><br><div>+ st.d S7, SP, S7_NUM * RSIZE</div><br><div>+ st.d S8, SP, S8_NUM * RSIZE</div><br><div>+</div><br><div>+ #</div><br><div>+ # save T0/SP from scratch registers on stack</div><br><div>+ #</div><br><div>+ csrrd T0, LOONGARCH_CSR_KS0</div><br><div>+ st.d T0, SP, T0_NUM * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_KS1</div><br><div>+ st.d T0, SP, SP_NUM * RSIZE</div><br><div>+</div><br><div>+ csrrd T0, LOONGARCH_CSR_CRMD</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_CRMD + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_PRMD</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_ECFG</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_ESTAT</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_ESTAT + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_EPC</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_EPC+ BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_BADV</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_BADV + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_BADI</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_BADI + BASE_NUM) * RSIZE</div><br><div>+ csrrd T0, LOONGARCH_CSR_EUEN</div><br><div>+ st.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE</div><br><div>+</div><br><div>+ #</div><br><div>+ # Save FPU context</div><br><div>+ #</div><br><div>+ ori T1, ZERO, CSR_EUEN_FPEN</div><br><div>+ and T2, T0, T1</div><br><div>+ beqz T2, 1f</div><br><div>+</div><br><div>+ fst.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fst.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+</div><br><div>+ movfcsr2gr T3, FCSR0</div><br><div>+ st.d T3, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ movcf2gr T3, $fcc0</div><br><div>+ or T2, T3, ZERO</div><br><div>+ movcf2gr T3, $fcc1</div><br><div>+ bstrins.d T2, T3, 0xf, 0x8</div><br><div>+ movcf2gr T3, $fcc2</div><br><div>+ bstrins.d T2, T3, 0x17, 0x10</div><br><div>+ movcf2gr T3, $fcc3</div><br><div>+ bstrins.d T2, T3, 0x1f, 0x18</div><br><div>+ movcf2gr T3, $fcc4</div><br><div>+ bstrins.d T2, T3, 0x27, 0x20</div><br><div>+ movcf2gr T3, $fcc5</div><br><div>+ bstrins.d T2, T3, 0x2f, 0x28</div><br><div>+ movcf2gr T3, $fcc6</div><br><div>+ bstrins.d T2, T3, 0x37, 0x30</div><br><div>+ movcf2gr T3, $fcc7</div><br><div>+ bstrins.d T2, T3, 0x3f, 0x38</div><br><div>+ st.d T2, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+1:</div><br><div>+ or A0, SP, ZERO</div><br><div>+ bl CommonExceptionEntry</div><br><div>+ /*disable interrupt*/</div><br><div>+ li.d T0, (1 << 2)</div><br><div>+ csrxchg ZERO, T0, LOONGARCH_CSR_CRMD</div><br><div>+</div><br><div>+ ld.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE</div><br><div>+ csrwr T0, LOONGARCH_CSR_PRMD</div><br><div>+ ld.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE</div><br><div>+ csrwr T0, LOONGARCH_CSR_ECFG</div><br><div>+ ld.d T0, SP, (LOONGARCH_CSR_EPC + BASE_NUM) * RSIZE</div><br><div>+ csrwr T0, LOONGARCH_CSR_EPC</div><br><div>+</div><br><div>+ ld.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE</div><br><div>+ ori T1, ZERO, CSR_EUEN_FPEN</div><br><div>+ and T2, T0, T1</div><br><div>+ beqz T2, 2f</div><br><div>+</div><br><div>+ #</div><br><div>+ # check previous FP state</div><br><div>+ # restore FP contect if FP enabled</div><br><div>+ #</div><br><div>+ fld.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ fld.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+</div><br><div>+ ld.d T0, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ movgr2fcsr FCSR0, T0</div><br><div>+ ld.d T0, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE</div><br><div>+ bstrpick.d T1, T0, 7, 0</div><br><div>+ movgr2cf $fcc0, T1</div><br><div>+ bstrpick.d T1, T0, 15, 8</div><br><div>+ movgr2cf $fcc1, T1</div><br><div>+ bstrpick.d T1, T0, 23, 16</div><br><div>+ movgr2cf $fcc2, T1</div><br><div>+ bstrpick.d T1, T0, 31, 24</div><br><div>+ movgr2cf $fcc3, T1</div><br><div>+ bstrpick.d T1, T0, 39, 32</div><br><div>+ movgr2cf $fcc4, T1</div><br><div>+ bstrpick.d T1, T0, 47, 40</div><br><div>+ movgr2cf $fcc5, T1</div><br><div>+ bstrpick.d T1, T0, 55, 48</div><br><div>+ movgr2cf $fcc6, T1</div><br><div>+ bstrpick.d T1, T0, 63, 56</div><br><div>+ movgr2cf $fcc7, T1</div><br><div>+2:</div><br><div>+ ld.d RA, SP, RA_NUM * RSIZE</div><br><div>+ ld.d GP, SP, GP_NUM * RSIZE</div><br><div>+ ld.d A0, SP, A0_NUM * RSIZE</div><br><div>+ ld.d A1, SP, A1_NUM * RSIZE</div><br><div>+ ld.d A2, SP, A2_NUM * RSIZE</div><br><div>+ ld.d A3, SP, A3_NUM * RSIZE</div><br><div>+ ld.d A4, SP, A4_NUM * RSIZE</div><br><div>+ ld.d A5, SP, A5_NUM * RSIZE</div><br><div>+ ld.d A6, SP, A6_NUM * RSIZE</div><br><div>+ ld.d A7, SP, A7_NUM * RSIZE</div><br><div>+ ld.d T0, SP, T0_NUM * RSIZE</div><br><div>+ ld.d T1, SP, T1_NUM * RSIZE</div><br><div>+ ld.d T2, SP, T2_NUM * RSIZE</div><br><div>+ ld.d T3, SP, T3_NUM * RSIZE</div><br><div>+ ld.d T4, SP, T4_NUM * RSIZE</div><br><div>+ ld.d T5, SP, T5_NUM * RSIZE</div><br><div>+ ld.d T6, SP, T6_NUM * RSIZE</div><br><div>+ ld.d T7, SP, T7_NUM * RSIZE</div><br><div>+ ld.d T8, SP, T8_NUM * RSIZE</div><br><div>+ ld.d TP, SP, TP_NUM * RSIZE</div><br><div>+ ld.d FP, SP, FP_NUM * RSIZE</div><br><div>+ ld.d S0, SP, S0_NUM * RSIZE</div><br><div>+ ld.d S1, SP, S1_NUM * RSIZE</div><br><div>+ ld.d S2, SP, S2_NUM * RSIZE</div><br><div>+ ld.d S3, SP, S3_NUM * RSIZE</div><br><div>+ ld.d S4, SP, S4_NUM * RSIZE</div><br><div>+ ld.d S5, SP, S5_NUM * RSIZE</div><br><div>+ ld.d S6, SP, S6_NUM * RSIZE</div><br><div>+ ld.d S7, SP, S7_NUM * RSIZE</div><br><div>+ ld.d S8, SP, S8_NUM * RSIZE</div><br><div>+</div><br><div>+ ld.d SP, SP, SP_NUM * RSIZE</div><br><div>+ ertn</div><br><div>+</div><br><div>+#</div><br><div>+# Exception trampoline copied down to RAM after initialization.</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(LoongArchException):</div><br><div>+ csrwr T0, LOONGARCH_CSR_KS0</div><br><div>+ csrwr SP, LOONGARCH_CSR_KS1</div><br><div>+ pcaddi T0, 0</div><br><div>+ ld.d T0, T0, 16</div><br><div>+ jirl ZERO, T0, 0</div><br><div>+ nop</div><br><div>+1:</div><br><div>+ .quad Exception_handler</div><br><div>+.globl LoongArchExceptionEnd</div><br><div>+LoongArchExceptionEnd:</div><br><div>+</div><br><div>+#</div><br><div>+# Set Exception Base Address.</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(SetEbase):</div><br><div>+ #</div><br><div>+ # clear Vint cofigure</div><br><div>+ # all exceptions share the same interrupt entry</div><br><div>+ #</div><br><div>+ csrrd T0, LOONGARCH_CSR_ECFG</div><br><div>+ li.d T1, ~0x70000</div><br><div>+ and T0, T0, T1</div><br><div>+ csrwr T0, LOONGARCH_CSR_ECFG</div><br><div>+</div><br><div>+ # set ebase</div><br><div>+ csrwr A0, LOONGARCH_CSR_EBASE</div><br><div>+ jirl ZERO, RA, 0</div><br><div>+</div><br><div>+#</div><br><div>+# Read Csr EUEN register.</div><br><div>+# @param A0 Pointer to the variable used to store the EUEN register value</div><br><div>+# @retval none</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(LoongArchReadqCsrEuen):</div><br><div>+ csrrd T0, LOONGARCH_CSR_EUEN</div><br><div>+ stptr.d T0, A0, 0</div><br><div>+ jirl ZERO, RA,0</div><br><div>+</div><br><div>+#</div><br><div>+# Write Csr EUEN register.</div><br><div>+# @param A0 The value used to write to the EUEN register</div><br><div>+# @retval none</div><br><div>+#</div><br><div>+</div><br><div>+ASM_PFX(LoongArchWriteqCsrEuen):</div><br><div>+ csrwr A0, LOONGARCH_CSR_EUEN</div><br><div>+ jirl ZERO, RA,0</div><br><div>--</div><br><div>2.31.1</div></div></blockquote>


 <div width="1" style="color:white;clear:both">_._,_._,_</div> <hr>   Groups.io Links:<p>   You receive all messages sent to this group.    <p> <a target="_blank" href="https://edk2.groups.io/g/devel/message/96294">View/Reply Online (#96294)</a> |    |  <a target="_blank" href="https://groups.io/mt/94955175/1813853">Mute This Topic</a>  | <a href="https://edk2.groups.io/g/devel/post">New Topic</a><br>    <a href="https://edk2.groups.io/g/devel/editsub/1813853">Your Subscription</a> | <a href="mailto:devel+owner@edk2.groups.io">Contact Group Owner</a> |  <a href="https://edk2.groups.io/g/devel/unsub">Unsubscribe</a>  [edk2-devel-archive@redhat.com]<br> <div width="1" style="color:white;clear:both">_._,_._,_</div>