From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from loongson.cn (loongson.cn [114.242.206.163]) by mx.groups.io with SMTP id smtpd.web09.3444.1665720097662409104 for ; Thu, 13 Oct 2022 21:01:38 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: loongson.cn, ip: 114.242.206.163, mailfrom: lixianglai@loongson.cn) Received: from localhost.localdomain (unknown [10.2.5.185]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Bx32sZ30hjMt8tAA--.26776S10; Fri, 14 Oct 2022 12:01:36 +0800 (CST) From: "xianglai" To: devel@edk2.groups.io Cc: quic_llindhol@quicinc.com, michael.d.kinney@intel.com, kraxel@redhat.com, ardb@kernel.org, maobibo@loongson.cn Subject: [edk2-platforms][PATCH V3 08/16] Platform/Loongson: Add CPU DXE driver. Date: Fri, 14 Oct 2022 12:01:21 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: AQAAf8Bx32sZ30hjMt8tAA--.26776S10 X-Coremail-Antispam: 1UD129KBjvAXoWDAFWxKr1kZw1xXF15XFyrJFb_yoWrZr4kAo W5Za9ayw47Jw18ta97G3Z7G3yxXF18uFs5XrsYvFsYgr90gF15CFW0y3ZxGw1fJF45XrZr JFy8X3Z7CFZIqrn3n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5ol0xt5qjotxo6or00hjvr0hdfq/ Content-Transfer-Encoding: quoted-printable The driver produces EFI_CPU_ARCH_PROTOCOL, Initialize the exception entry address. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4054 Signed-off-by: xianglai li --- .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c | 382 ++++++++++++++++++ .../LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h | 151 +++++++ .../Drivers/CpuDxe/CpuDxe.inf | 56 +++ .../Drivers/CpuDxe/LoongArch64/Exception.c | 338 ++++++++++++++++ .../Drivers/CpuDxe/LoongArch64/Fpu.S | 67 +++ .../Drivers/CpuDxe/LoongArch64/LoongArch.S | 292 +++++++++++++ 6 files changed, 1286 insertions(+) create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDx= e.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDx= e.h create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDx= e.inf create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/Loong= Arch64/Exception.c create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/Loong= Arch64/Fpu.S create mode 100644 Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/Loong= Arch64/LoongArch.S diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.c b/P= latform/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=0D + CPU DXE Module to produce CPU ARCH Protocol=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "CpuDxe.h"=0D +=0D +BOOLEAN mInterruptState =3D FALSE;=0D +=0D +/*=0D + This function flushes the range of addresses from Start to Start+Length= =0D + from the processor's data cache. If Start is not aligned to a cache line= =0D + boundary, then the bytes before Start to the preceding cache line bounda= ry=0D + are also flushed. If Start+Length is not aligned to a cache line boundar= y,=0D + then the bytes past Start+Length to the end of the next cache line bound= ary=0D + are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate mu= st be=0D + supported. If the data cache is fully coherent with all DMA operations, = then=0D + this function can just return EFI_SUCCESS. If the processor does not sup= port=0D + flushing a range of the data cache, then the entire data cache can be fl= ushed.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D + @param Start The beginning physical address to flush from th= e processor's data=0D + cache.=0D + @param Length The number of bytes to flush from the processor= 's data cache. This=0D + function may flush more bytes than Length speci= fies depending upon=0D + the granularity of the flush operation that the= processor supports.=0D + @param FlushType Specifies the type of flush operation to perfor= m.=0D +=0D + @retval EFI_SUCCESS The address range from Start to Start+Leng= th was flushed from=0D + the processor's data cache.=0D + @retval EFI_UNSUPPORTEDT The processor does not support the cache f= lush type specified=0D + by FlushType.=0D + @retval EFI_DEVICE_ERROR The address range from Start to Start+Leng= th could not be flushed=0D + from the processor's data cache.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuFlushCpuDataCache (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN EFI_PHYSICAL_ADDRESS Start,=0D + IN UINT64 Length,=0D + IN EFI_CPU_FLUSH_TYPE FlushType=0D + )=0D +{=0D +=0D + switch (FlushType) {=0D + case EfiCpuFlushTypeWriteBack:=0D + WriteBackDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);=0D + break;=0D + case EfiCpuFlushTypeInvalidate:=0D + InvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Length);=0D + break;=0D + case EfiCpuFlushTypeWriteBackInvalidate:=0D + WriteBackInvalidateDataCacheRange ((VOID *) (UINTN)Start, (UINTN)Len= gth);=0D + break;=0D + default:=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This function enables interrupt processing by the processor.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D +=0D + @retval EFI_SUCCESS Interrupts are enabled on the processor.=0D + @retval EFI_DEVICE_ERROR Interrupts could not be enabled on the pro= cessor.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuEnableInterrupt (=0D + IN EFI_CPU_ARCH_PROTOCOL *This=0D + )=0D +{=0D + EnableInterrupts ();=0D +=0D + mInterruptState =3D TRUE;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This function disables interrupt processing by the processor.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D +=0D + @retval EFI_SUCCESS Interrupts are disabled on the processor.= =0D + @retval EFI_DEVICE_ERROR Interrupts could not be disabled on the pr= ocessor.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuDisableInterrupt (=0D + IN EFI_CPU_ARCH_PROTOCOL *This=0D + )=0D +{=0D + DisableInterrupts ();=0D +=0D + mInterruptState =3D FALSE;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This function retrieves the processor's current interrupt state a return= s it in=0D + State. If interrupts are currently enabled, then TRUE is returned. If in= terrupts=0D + are currently disabled, then FALSE is returned.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D + @param State A pointer to the processor's current interrupt = state. Set to TRUE if=0D + interrupts are enabled and FALSE if interrupts = are disabled.=0D +=0D + @retval EFI_SUCCESS The processor's current interrupt state wa= s returned in State.=0D + @retval EFI_INVALID_PARAMETER State is NULL.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuGetInterruptState (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + OUT BOOLEAN *State=0D + )=0D +{=0D + if (State =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + *State =3D mInterruptState;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +=0D +/**=0D + This function generates an INIT on the processor. If this function succe= eds, then the=0D + processor will be reset, and control will not be returned to the caller.= If InitType is=0D + not supported by this processor, or the processor cannot programmaticall= y generate an=0D + INIT without help from external hardware, then EFI_UNSUPPORTED is return= ed. If an error=0D + occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned= .=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D + @param InitType The type of processor INIT to perform.=0D +=0D + @retval EFI_SUCCESS The processor INIT was performed. This ret= urn code should never be seen.=0D + @retval EFI_UNSUPPORTED The processor INIT operation specified by = InitType is not supported=0D + by this processor.=0D + @retval EFI_DEVICE_ERROR The processor INIT failed.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuInit (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN EFI_CPU_INIT_TYPE InitType=0D + )=0D +{=0D + return EFI_UNSUPPORTED;=0D +}=0D +=0D +/**=0D + This function registers and enables the handler specified by InterruptHa= ndler for a processor=0D + interrupt or exception type specified by InterruptType. If InterruptHand= ler is NULL, then the=0D + handler for the processor interrupt or exception type specified by Inter= ruptType is uninstalled.=0D + The installed handler is called once for each processor interrupt or exc= eption.=0D +=0D + @param InterruptType Interrupt Type.=0D + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRU= PT_HANDLER that is called=0D + when a processor interrupt occurs. If this parameter is NULL, then the h= andler=0D + will be uninstalled.=0D +=0D + @retval EFI_SUCCESS The handler for the processor interrupt wa= s successfully installed or uninstalled.=0D + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handle= r for InterruptType was=0D + previously installed.=0D + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo= r InterruptType was not=0D + previously installed.=0D + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType i= s not supported.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuRegisterInterruptHandler (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN EFI_EXCEPTION_TYPE InterruptType,=0D + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler=0D + )=0D +{=0D +=0D + return RegisterInterruptHandler (InterruptType, InterruptHandler);=0D +}=0D +=0D +/**=0D + Returns a timer value from one of the CPU's internal timers. There is no= =0D + inherent time interval between ticks but is a function of the CPU freque= ncy.=0D +=0D + @param This - Protocol instance structure.=0D + @param TimerIndex - Specifies which CPU timer is requested.=0D + @param TimerValue - Pointer to the returned timer value.=0D + @param TimerPeriod - A pointer to the amount of time that passe= s=0D + in femtoseconds (10-15) for each increment= =0D + of TimerValue. If TimerValue does not=0D + increment at a predictable rate, then 0 is= =0D + returned. The amount of time that has=0D + passed between two calls to GetTimerValue(= )=0D + can be calculated with the formula=0D + (TimerValue2 - TimerValue1) * TimerPeriod.= =0D + This parameter is optional and may be NULL= .=0D +=0D + @retval EFI_SUCCESS - If the CPU timer count was returned.=0D + @retval EFI_UNSUPPORTED - If the CPU does not have any readable ti= mers.=0D + @retval EFI_DEVICE_ERROR - If an error occurred while reading the t= imer.=0D + @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerValue is= NULL.=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuGetTimerValue (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN UINT32 TimerIndex,=0D + OUT UINT64 *TimerValue,=0D + OUT UINT64 *TimerPeriod OPTIONAL=0D + )=0D +{=0D + return EFI_UNSUPPORTED;=0D +}=0D +/**=0D + This function modifies the attributes for the memory region specified by= BaseAddress and=0D + Length from their current attributes to the attributes specified by Attr= ibutes.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D + @param BaseAddress The physical address that is the start address = of a memory region.=0D + @param Length The size in bytes of the memory region.=0D + @param Attributes The bit mask of attributes to set for the memor= y region.=0D +=0D + @retval EFI_SUCCESS The attributes were set for the memory reg= ion.=0D + @retval EFI_ACCESS_DENIED The attributes for the memory resource ran= ge specified by=0D + BaseAddress and Length cannot be modified.= =0D + @retval EFI_INVALID_PARAMETER Length is zero.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to m= odify the attributes of=0D + the memory resource range.=0D + @retval EFI_UNSUPPORTED The processor does not support one or more= bytes of the memory=0D + resource range specified by BaseAddress an= d Length.=0D + The bit mask of attributes is not support = for the memory resource=0D + range specified by BaseAddress and Length.= =0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuSetMemoryAttributes (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 EfiAttributes=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN LoongArchAttributes;=0D + UINTN RegionBaseAddress;=0D + UINTN RegionLength;=0D + UINTN RegionLoongArchAttributes;=0D +=0D + if ((BaseAddress & (SIZE_4KB - 1)) !=3D 0) {=0D + // Minimum granularity is SIZE_4KB (4KB on ARM)=0D + DEBUG ((DEBUG_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum gr= anularity is SIZE_4KB\n",=0D + BaseAddress,=0D + Length,=0D + EfiAttributes));=0D +=0D + return EFI_UNSUPPORTED;=0D + }=0D + // Convert the 'Attribute' into LoongArch Attribute=0D + LoongArchAttributes =3D EfiAttributeToLoongArchAttribute (EfiAttributes)= ;=0D +=0D + // Get the region starting from 'BaseAddress' and its 'Attribute'=0D + RegionBaseAddress =3D BaseAddress;=0D + Status =3D GetLoongArchMemoryRegion (RegionBaseAddress, BaseAddress + Le= ngth,=0D + &RegionLength, &RegionLoongArchAttributes);=0D +=0D + LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttributes);=0D + // Data & Instruction Caches are flushed when we set new memory attribut= es.=0D + // So, we only set the attributes if the new region is different.=0D + if (EFI_ERROR (Status) || (RegionLoongArchAttributes !=3D LoongArchAttri= butes) ||=0D + ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))=0D + {=0D + return LoongArchSetMemoryAttributes (BaseAddress, Length, EfiAttribute= s);=0D + }=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Callback function for idle events.=0D +=0D + @param Event Event whose notification function is being= invoked.=0D + @param Context The pointer to the notification function's= context,=0D + which is implementation-dependent.=0D +=0D + @param VOID=0D +**/=0D +VOID=0D +EFIAPI=0D +IdleLoopEventCallback (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + CpuSleep ();=0D +}=0D +=0D +//=0D +// Globals used to initialize the protocol=0D +//=0D +EFI_HANDLE CpuHandle =3D NULL;=0D +EFI_CPU_ARCH_PROTOCOL Cpu =3D {=0D + CpuFlushCpuDataCache,=0D + CpuEnableInterrupt,=0D + CpuDisableInterrupt,=0D + CpuGetInterruptState,=0D + CpuInit,=0D + CpuRegisterInterruptHandler,=0D + CpuGetTimerValue,=0D + CpuSetMemoryAttributes,=0D + 0, // NumberOfTimers=0D + 4, // DmaBufferAlignment=0D +};=0D +=0D +=0D +/**=0D + Initialize the state information for the CPU Architectural Protocol.=0D +=0D + @param ImageHandle Image handle this driver.=0D + @param SystemTable Pointer to the System Table.=0D +=0D + @retval EFI_SUCCESS Thread can be successfully created=0D + @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure=0D + @retval EFI_DEVICE_ERROR Cannot create the thread=0D +**/=0D +EFI_STATUS=0D +CpuDxeInitialize (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_EVENT IdleLoopEvent;=0D +=0D + InitializeExceptions (&Cpu);=0D +=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &CpuHandle,=0D + &gEfiCpuArchProtocolGuid, &Cpu,=0D + NULL=0D + );=0D +=0D + //=0D + // Setup a callback for idle events=0D + //=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_NOTIFY,=0D + IdleLoopEventCallback,=0D + NULL,=0D + &gIdleLoopEventGuid,=0D + &IdleLoopEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D diff --git a/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h b/P= latform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h new file mode 100644 index 0000000000..1bb51bce24 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/CpuDxe.h @@ -0,0 +1,151 @@ +/** @file=0D + CPU DXE Module to produce CPU ARCH Protocol and CPU MP Protocol=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef CPU_DXE_H_=0D +#define CPU_DXE_H_=0D +=0D +#include =0D +=0D +/**=0D + This function registers and enables the handler specified by InterruptHa= ndler for a processor=0D + interrupt or exception type specified by InteruptNum. If InterruptHandle= r is NULL, then the=0D + handler for the processor interrupt or exception type specified by Inter= uptNum is uninstalled.=0D + The installed handler is called once for each processor interrupt or exc= eption.=0D +=0D + @param InteruptNum A number of the processor's current interrupt.=0D + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRU= PT_HANDLER that is called=0D + when a processor interrupt occurs. If this para= meter is NULL, then the handler=0D + will be uninstalled.=0D +=0D + @retval EFI_SUCCESS The handler for the processor interrupt wa= s successfully installed or uninstalled.=0D + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handle= r for InteruptNum was=0D + previously installed.=0D + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo= r InteruptNum was not=0D + previously installed.=0D + @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is = not supported.=0D +=0D +**/=0D +EFI_STATUS=0D +RegisterInterruptHandler (=0D + IN EFI_EXCEPTION_TYPE InteruptNum,=0D + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler=0D + );=0D +=0D +=0D +/**=0D + This function registers and enables the handler specified by InterruptHa= ndler for a processor=0D + interrupt or exception type specified by InteruptNum. If InterruptHandle= r is NULL, then the=0D + handler for the processor interrupt or exception type specified by Inter= uptNum is uninstalled.=0D + The installed handler is called once for each processor interrupt or exc= eption.=0D +=0D + @param InteruptNum A number of the processor's current interrupt.=0D + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRU= PT_HANDLER that is called=0D + when a processor interrupt occurs. If this para= meter is NULL, then the handler=0D + will be uninstalled.=0D +=0D + @retval EFI_SUCCESS The handler for the processor interrupt wa= s successfully installed or uninstalled.=0D + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handle= r for InteruptNum was=0D + previously installed.=0D + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo= r InteruptNum was not=0D + previously installed.=0D + @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is = not supported.=0D +=0D +**/=0D +EFI_STATUS=0D +RegisterDebuggerInterruptHandler (=0D + IN EFI_EXCEPTION_TYPE InteruptNum,=0D + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler=0D + );=0D +=0D +/**=0D + This function modifies the attributes for the memory region specified by= BaseAddress and=0D + Length from their current attributes to the attributes specified by Attr= ibutes.=0D +=0D + @param This The EFI_CPU_ARCH_PROTOCOL instance.=0D + @param BaseAddress The physical address that is the start address = of a memory region.=0D + @param Length The size in bytes of the memory region.=0D + @param Attributes The bit mask of attributes to set for the memor= y region.=0D +=0D + @retval EFI_SUCCESS The attributes were set for the memory reg= ion.=0D + @retval EFI_ACCESS_DENIED The attributes for the memory resource ran= ge specified by=0D + BaseAddress and Length cannot be modified.= =0D + @retval EFI_INVALID_PARAMETER Length is zero.=0D + @retval EFI_OUT_OF_RESOURCES There are not enough system resources to m= odify the attributes of=0D + the memory resource range.=0D + @retval EFI_UNSUPPORTED The processor does not support one or more= bytes of the memory=0D + resource range specified by BaseAddress an= d Length.=0D + The bit mask of attributes is not support = for the memory resource=0D + range specified by BaseAddress and Length.= =0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +CpuSetMemoryAttributes (=0D + IN EFI_CPU_ARCH_PROTOCOL *This,=0D + IN EFI_PHYSICAL_ADDRESS BaseAddress,=0D + IN UINT64 Length,=0D + IN UINT64 Attributes=0D + );=0D +=0D +/** Exception module initialization=0D + This function sets the exception base address.=0D +=0D + @param Cpu A pointer to the CPU architecture protocol structure.=0D +=0D + @retval EFI_SUCCESS Initialization succeeded=0D + @retval EFI_NOT_FOUND Could not Found resources.=0D + @retval EFI_OUT_OF_RESOURCES No enough resources.=0D +**/=0D +EFI_STATUS=0D +InitializeExceptions (=0D + IN EFI_CPU_ARCH_PROTOCOL *Cpu=0D + );=0D +=0D +/** Common exception entry=0D + Exception handling is the entry point for the C environment,=0D + This function does different things depending on the exception type.=0D +=0D + @param SystemContext The system context at the time of the exception.= =0D +=0D + @retval VOID.=0D +**/=0D +VOID=0D +EFIAPI=0D +CommonExceptionEntry (=0D + IN OUT EFI_SYSTEM_CONTEXT SystemContext=0D + );=0D +=0D +extern CHAR8 LoongArchException[], LoongArchExceptionEnd[];=0D +/** Set Exception Base Address=0D +=0D + @param addr Exception Base Address.=0D +=0D + @retval The Old Exception Base Address.=0D +**/=0D +extern=0D +UINT64=0D +SetEbase (=0D + EFI_PHYSICAL_ADDRESS addr=0D + );=0D +/*=0D + Load the FPU with signalling NANS. This bit pattern we're using has=0D + the property that no matter whether considered as single or as double=0D + precision represents signaling NANS.=0D +=0D + @param fcsr The value to initialize FCSR0=0D +=0D + @retval The Old Exception Base Address.=0D + */=0D +extern=0D +VOID=0D +InitFpu (=0D + UINT32 fcsr=0D + );=0D +=0D +#endif // __CPU_DXE_H__=0D 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=0D +# CPU driver installs CPU Architecture Protocol and CPU MP protocol.=0D +#=0D +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights = reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D CpuDxe=0D + FILE_GUID =3D bf954921-25c1-48c0-9bfb-8d0cd7ee92da= =0D + MODULE_TYPE =3D DXE_DRIVER=0D + VERSION_STRING =3D 1.0=0D +=0D + ENTRY_POINT =3D CpuDxeInitialize=0D +=0D +[Sources.Common]=0D + CpuDxe.c=0D + CpuDxe.h=0D +=0D +[Sources.LOONGARCH64]=0D + LoongArch64/Exception.c=0D + LoongArch64/LoongArch.S=0D + LoongArch64/Fpu.S=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + EmbeddedPkg/EmbeddedPkg.dec=0D + Platform/Loongson/LoongArchQemuPkg/Loongson.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + BaseMemoryLib=0D + CacheMaintenanceLib=0D + CpuLib=0D + DebugLib=0D + DxeServicesTableLib=0D + HobLib=0D + PeCoffGetEntryPointLib=0D + UefiDriverEntryPoint=0D + UefiLib=0D + MmuLib=0D +=0D +[Protocols]=0D + gEfiCpuArchProtocolGuid=0D + gEfiMpServiceProtocolGuid=0D +=0D +[Guids]=0D + gEfiDebugImageInfoTableGuid=0D + gIdleLoopEventGuid=0D +=0D +[Depex]=0D + TRUE=0D 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..431aa39607 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/Excepti= on.c @@ -0,0 +1,338 @@ +/** @file=0D +=0D + Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D + @par Glossary:=0D + - ESTAT - Exception Status=0D + - ECFG - Exception Configure=0D + - ERA - Exception Return Address=0D + - BADV - Bad Virtual Address=0D + - BADI - Bad Instructions=0D + - Epc or EPC or epc - Exception Program Counter=0D + - pc or PC or pc - Program Counter=0D + - CRMD - Current Mode=0D + - PRMD - Previous Mode=0D + - CsrEuen - Cpu Status Register Extern Unit Enable=0D + - fpu or fp or FP - Float Point Unit=0D + - LOONGARCH - Loongson Arch=0D + - Irq - Interrupt ReQuest=0D +**/=0D +=0D +#include "Library/Cpu.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include "CpuDxe.h"=0D +#include =0D +#include =0D +#include =0D +=0D +=0D +=0D +EFI_EXCEPTION_CALLBACK gInterruptHandler[MAX_LOONGARCH_INTERRUPT + 1];=0D +EFI_EXCEPTION_CALLBACK gDebuggerExceptionHandlers[MAX_LOONGARCH_INTERRUPT= + 1];=0D +=0D +/**=0D + This function registers and enables the handler specified by InterruptHa= ndler for a processor=0D + interrupt or exception type specified by InteruptNum. If InterruptHandle= r is NULL, then the=0D + handler for the processor interrupt or exception type specified by Inter= uptNum is uninstalled.=0D + The installed handler is called once for each processor interrupt or exc= eption.=0D +=0D + @param InteruptNum A number of the processor's current interrupt.=0D + @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRU= PT_HANDLER that is called=0D + when a processor interrupt occurs. If this para= meter is NULL, then the handler=0D + will be uninstalled.=0D +=0D + @retval EFI_SUCCESS The handler for the processor interrupt wa= s successfully installed or uninstalled.=0D + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handle= r for InteruptNum was=0D + previously installed.=0D + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler fo= r InteruptNum was not=0D + previously installed.=0D + @retval EFI_UNSUPPORTED The interrupt specified by InteruptNum is = not supported.=0D +=0D +**/=0D +EFI_STATUS=0D +RegisterInterruptHandler (=0D + IN EFI_EXCEPTION_TYPE InteruptNum,=0D + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler=0D + )=0D +{=0D + if (InteruptNum > MAX_LOONGARCH_INTERRUPT) {=0D + return EFI_UNSUPPORTED;=0D + }=0D +=0D + if ((InterruptHandler !=3D NULL)=0D + && (gInterruptHandler[InteruptNum] !=3D NULL))=0D + {=0D + return EFI_ALREADY_STARTED;=0D + }=0D +=0D + gInterruptHandler[InteruptNum] =3D InterruptHandler;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +/**=0D + This function calls the corresponding exception handler based on the exc= eption type.=0D +=0D + @param SystemContext The system context at the time of the exception.= =0D +=0D + @retval VOID=0D +**/=0D +STATIC VOID=0D +EFIAPI=0D +CommonInterruptHandler (=0D + IN OUT EFI_SYSTEM_CONTEXT SystemContext=0D + )=0D +{=0D + INT32 Pending;=0D + INT32 InterruptNum;=0D + /*Interrupt [13-0] NMI IPI TI PCOV hw IP10-IP2 soft IP1-IP0*/=0D + Pending =3D ((SystemContext.SystemContextLoongArch64->ESTAT) &=0D + (SystemContext.SystemContextLoongArch64->ECFG) & 0x1fff);=0D + for (InterruptNum =3D 0; InterruptNum < MAX_LOONGARCH_INTERRUPT; Interru= ptNum++) {=0D + if (Pending & (1 << InterruptNum)) {=0D + if (gInterruptHandler[InterruptNum] !=3D NULL) {=0D + gInterruptHandler[InterruptNum] (InterruptNum, SystemContext);=0D + } else {=0D + DEBUG ((DEBUG_INFO, "Pending: 0x%0x, InterruptNum: 0x%0x\n", Pendi= ng, InterruptNum));=0D + }=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Use the EFI Debug Image Table to lookup the FaultAddress and find which = PE/COFF image=0D + it came from. As long as the PE/COFF image contains a debug directory en= try a=0D + string can be returned. For ELF and Mach-O images the string points to t= he Mach-O or ELF=0D + image. Microsoft tools contain a pointer to the PDB file that contains t= he debug information.=0D +=0D + @param FaultAddress Address to find PE/COFF image for.=0D + @param ImageBase Return load address of found image=0D + @param PeCoffSizeOfHeaders Return the size of the PE/COFF header for t= he image that was found=0D +=0D + @retval NULL FaultAddress not in a loaded PE/COFF image.= =0D + @retval Path and file name of PE/COFF image.=0D +=0D +**/=0D +CHAR8 *=0D +GetImageName (=0D + IN UINTN FaultAddress,=0D + OUT UINTN *ImageBase,=0D + OUT UINTN *PeCoffSizeOfHeaders=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugTableHeader;=0D + EFI_DEBUG_IMAGE_INFO *DebugTable;=0D + UINTN Entry;=0D + CHAR8 *Address;=0D +=0D + Status =3D EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid,= (VOID **)&DebugTableHeader);=0D + if (EFI_ERROR (Status)) {=0D + return NULL;=0D + }=0D +=0D + DebugTable =3D DebugTableHeader->EfiDebugImageInfoTable;=0D + if (DebugTable =3D=3D NULL) {=0D + return NULL;=0D + }=0D +=0D + Address =3D (CHAR8 *)(UINTN)FaultAddress;=0D + for (Entry =3D 0; Entry < DebugTableHeader->TableSize; Entry++, DebugTab= le++) {=0D + if (DebugTable->NormalImage !=3D NULL) {=0D + if ((DebugTable->NormalImage->ImageInfoType =3D=3D EFI_DEBUG_IMAGE_I= NFO_TYPE_NORMAL) &&=0D + (DebugTable->NormalImage->LoadedImageProtocolInstance !=3D NULL)= ) {=0D + if ((Address >=3D (CHAR8 *)DebugTable->NormalImage->LoadedImagePro= tocolInstance->ImageBase) &&=0D + (Address <=3D ((CHAR8 *)DebugTable->NormalImage->LoadedImagePr= otocolInstance->ImageBase + DebugTable->NormalImage->LoadedImageProtocolIns= tance->ImageSize))) {=0D + *ImageBase =3D (UINTN)DebugTable->NormalImage->LoadedImageProtoc= olInstance->ImageBase;=0D + *PeCoffSizeOfHeaders =3D PeCoffGetSizeOfHeaders ((VOID *)(UINTN)= *ImageBase);=0D + return PeCoffLoaderGetPdbPointer (DebugTable->NormalImage->Loade= dImageProtocolInstance->ImageBase);=0D + }=0D + }=0D + }=0D + }=0D +=0D + return NULL;=0D +}=0D +=0D +/**=0D + pass a file name string that contains the path, return file name.=0D +=0D + @param FullName Path and file name=0D +=0D + @retval file name.=0D +**/=0D +STATIC=0D +CONST CHAR8 *=0D +BaseName (=0D + IN CONST CHAR8 *FullName=0D + )=0D +{=0D + CONST CHAR8 *Str;=0D +=0D + Str =3D FullName + AsciiStrLen (FullName);=0D +=0D + while (--Str > FullName) {=0D + if (*Str =3D=3D '/' || *Str =3D=3D '\\') {=0D + return Str + 1;=0D + }=0D + }=0D + return Str;=0D +}=0D +=0D +/** Default Exception Handler Function=0D + This function is called when an exception occurs that cannot be handled,= =0D + and this function prints the system context information when the interru= pt occurred=0D +=0D + @param SystemContext The system context at the time of the exception.= =0D +=0D + @retval VOID.=0D +**/=0D +STATIC=0D +VOID=0D +EFIAPI=0D +DefaultHandler (=0D + IN OUT EFI_SYSTEM_CONTEXT SystemContext=0D + )=0D +{=0D + CHAR8 *ImageName;=0D + UINTN ImageBase, Epc;=0D + UINTN PeCoffSizeOfHeader;=0D +=0D + DEBUG ((DEBUG_ERROR, "CRMD 0x%llx\n", SystemContext.SystemContextLoon= gArch64->CRMD));=0D + DEBUG ((DEBUG_ERROR, "PRMD 0x%llx\n", SystemContext.SystemContextLoon= gArch64->PRMD));=0D + DEBUG ((DEBUG_ERROR, "ECFG 0x%llx\n", SystemContext.SystemContextLoong= Arch64->ECFG));=0D + DEBUG ((DEBUG_ERROR, "ESTAT 0x%llx\n", SystemContext.SystemContextLoo= ngArch64->ESTAT));=0D + DEBUG ((DEBUG_ERROR, "ERA 0x%llx\n", SystemContext.SystemContextLoon= gArch64->ERA));=0D + DEBUG ((DEBUG_ERROR, "BADV 0x%llx\n", SystemContext.SystemContextLoo= ngArch64->BADV));=0D + DEBUG ((DEBUG_ERROR, "BADI 0x%llx\n", SystemContext.SystemContextLoongA= rch64->BADI));=0D +=0D + Epc =3D SystemContext.SystemContextLoongArch64->ERA;=0D + ImageName =3D GetImageName (Epc, &ImageBase, &PeCoffSizeOfHeader);=0D + if (ImageName !=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "PC 0x%012lx (0x%012lx+0x%08x) [ 0] %a\n",=0D + Epc, ImageBase,=0D + Epc - ImageBase, BaseName (ImageName)));=0D + } else {=0D + DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Epc));=0D + }=0D +=0D + while (1);=0D +}=0D +=0D +/** Common exception entry=0D + Exception handling is the entry point for the C environment,=0D + This function does different things depending on the exception type.=0D +=0D + @param SystemContext The system context at the time of the exception.= =0D +=0D + @retval VOID.=0D +**/=0D +VOID=0D +EFIAPI=0D +CommonExceptionEntry (=0D + IN OUT EFI_SYSTEM_CONTEXT SystemContext=0D + )=0D +{=0D + INT32 ExceptionType;=0D + UINT64 CsrEuen, FpuStatus;=0D +=0D + ExceptionType =3D SystemContext.SystemContextLoongArch64->ESTAT & CSR_ES= TAT_EXC;=0D + ExceptionType =3D ExceptionType >> CSR_ESTAT_EXC_SHIFT;=0D +=0D + LOONGARCH_CSR_READQ (CsrEuen, LOONGARCH_CSR_EUEN);=0D + FpuStatus =3D CsrEuen & CSR_EUEN_FPEN;=0D + switch (ExceptionType) {=0D + case EXC_INT:=0D + /*=0D + * handle interrupt exception=0D + */=0D + CommonInterruptHandler (SystemContext);=0D + if (!FpuStatus) {=0D + LOONGARCH_CSR_READQ (CsrEuen, LOONGARCH_CSR_EUEN);=0D + if (CsrEuen & CSR_EUEN_FPEN) {=0D + /*=0D + * Since Hw FP is enabled during interrupt handler,=0D + * disable FP=0D + */=0D + CsrEuen &=3D ~CSR_EUEN_FPEN;=0D + LOONGARCH_CSR_WRITEQ (CsrEuen, LOONGARCH_CSR_EUEN);=0D + }=0D + }=0D + break;=0D + case EXC_FPDIS:=0D + /*=0D + * Hardware FP disabled exception,=0D + * Enable and init FP registers here=0D + */=0D + LOONGARCH_ENABLR_FPU ();=0D + InitFpu(FPU_CSR_RN);=0D + break;=0D + default:=0D + DefaultHandler(SystemContext);=0D + break;=0D + }=0D +}=0D +=0D +/** Exception module initialization=0D + This function sets the exception base address.=0D +=0D + @param Cpu A pointer to the CPU architecture protocol structure.=0D +=0D + @retval EFI_SUCCESS Initialization succeeded=0D + @retval EFI_NOT_FOUND Could not Found resources.=0D + @retval EFI_OUT_OF_RESOURCES No enough resources.=0D +**/=0D +EFI_STATUS=0D +InitializeExceptions (=0D + IN EFI_CPU_ARCH_PROTOCOL *Cpu=0D + )=0D +{=0D + EFI_STATUS Status;=0D + BOOLEAN IrqEnabled;=0D + EFI_PHYSICAL_ADDRESS Address;=0D +=0D + ZeroMem (gInterruptHandler, sizeof (*gInterruptHandler));=0D +=0D + //=0D + // Disable interrupts=0D + //=0D + Cpu->GetInterruptState (Cpu, &IrqEnabled);=0D + Cpu->DisableInterrupt (Cpu);=0D +=0D + //=0D + // EFI does not use the FIQ, but a debugger might so we must disable=0D + // as we take over the exception vectors.=0D + //=0D + Status =3D gBS->AllocatePages (=0D + AllocateAnyPages,=0D + EfiRuntimeServicesData,=0D + 1,=0D + &Address=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "Set Exception Base Address\n"));=0D + CopyMem ((char *)Address, LoongArchException, (LoongArchExceptionEnd - L= oongArchException));=0D + InvalidateInstructionCacheRange ((char *)Address, (LoongArchExceptionEnd= - LoongArchException));=0D +=0D + SetEbase (Address);=0D + DEBUG ((DEBUG_INFO, "LoongArchException address: 0x%p\n", Address));=0D + DEBUG ((DEBUG_INFO, "LoongArchExceptionEnd address: 0x%p\n", Address + (= LoongArchExceptionEnd - LoongArchException)));=0D +=0D + DEBUG ((DEBUG_INFO, "InitializeExceptions, IrqEnabled =3D %x\n", IrqEnab= led));=0D + if (IrqEnabled) {=0D + //=0D + // Restore interrupt state=0D + //=0D + Status =3D Cpu->EnableInterrupt (Cpu);=0D + }=0D +=0D + return Status;=0D +}=0D 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 @@ +#-------------------------------------------------------------------------= -----=0D +#=0D +# Fpu for LoongArch=0D +#=0D +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +# @par Glossary:=0D +# - CsrEuen - Cpu Status Register Extern Unit Enable=0D +# - FPEN - FPU Enable=0D +# - fpu or fp or FP - Float Point Unit=0D +#-------------------------------------------------------------------------= ----=0D +#ifndef __ASSEMBLY__=0D +#define __ASSEMBLY__=0D +#endif=0D +#include "Library/Cpu.h"=0D +#include "CpuDxe.h"=0D +#include "LoongArchAsmMacro.h"=0D +=0D +/*=0D + Load the FPU with signalling NANS. This bit pattern we're using has=0D + the property that no matter whether considered as single or as double=0D + precision represents signaling NANS.=0D +=0D + The value to initialize FCSR0 to comes in $A0.=0D + */=0D +ASM_FUNC(InitFpu)=0D + li.d T1, CSR_EUEN_FPEN=0D + csrxchg T1, T1, LOONGARCH_CSR_EUEN=0D +=0D + movgr2fcsr FCSR0, A0=0D + li.d T1, -1 # SNaN=0D + movgr2fr.d $f0, T1=0D + movgr2fr.d $f1, T1=0D + movgr2fr.d $f2, T1=0D + movgr2fr.d $f3, T1=0D + movgr2fr.d $f4, T1=0D + movgr2fr.d $f5, T1=0D + movgr2fr.d $f6, T1=0D + movgr2fr.d $f7, T1=0D + movgr2fr.d $f8, T1=0D + movgr2fr.d $f9, T1=0D + movgr2fr.d $f10, T1=0D + movgr2fr.d $f11, T1=0D + movgr2fr.d $f12, T1=0D + movgr2fr.d $f13, T1=0D + movgr2fr.d $f14, T1=0D + movgr2fr.d $f15, T1=0D + movgr2fr.d $f16, T1=0D + movgr2fr.d $f17, T1=0D + movgr2fr.d $f18, T1=0D + movgr2fr.d $f19, T1=0D + movgr2fr.d $f20, T1=0D + movgr2fr.d $f21, T1=0D + movgr2fr.d $f22, T1=0D + movgr2fr.d $f23, T1=0D + movgr2fr.d $f24, T1=0D + movgr2fr.d $f25, T1=0D + movgr2fr.d $f26, T1=0D + movgr2fr.d $f27, T1=0D + movgr2fr.d $f28, T1=0D + movgr2fr.d $f29, T1=0D + movgr2fr.d $f30, T1=0D + movgr2fr.d $f31, T1=0D +=0D + jirl ZERO, RA, 0=0D 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..ae3e00b870 --- /dev/null +++ b/Platform/Loongson/LoongArchQemuPkg/Drivers/CpuDxe/LoongArch64/LoongAr= ch.S @@ -0,0 +1,292 @@ +#-------------------------------------------------------------------------= -----=0D +#=0D +# LoongArch for LoongArch=0D +#=0D +# Copyright (c) 2021 Loongson Technology Corporation Limited. All rights r= eserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +# @par Glossary:=0D +# - CsrEuen - Cpu Status Register Extern Unit Enable=0D +# - fpu - Float Point Unit=0D +# - LOONGARCH - Loongson Arch=0D +# - Ebase - Exception Base Address=0D +#-------------------------------------------------------------------------= ----=0D +=0D +#ifndef __ASSEMBLY__=0D +#define __ASSEMBLY__=0D +#endif=0D +=0D +#include "Library/Cpu.h"=0D +#include "CpuDxe.h"=0D +#include "LoongArchAsmMacro.h"=0D +=0D +#define RSIZE 8 /* 64 bit mode register size */=0D +#define RLOGSIZE 3=0D +=0D +=0D +/*=0D + Main exception handler. Not really a leaf routine but not a normal=0D + function either. Save away the entire cpu state end enter exception mod= e.=0D + */=0D +ASM_FUNC(Exception_handler)=0D +=0D + csrrd SP, LOONGARCH_CSR_KS1=0D +=0D + addi.d T0, $r0, -0x10=0D + and SP, SP, T0=0D + addi.d SP, SP, -((CSR_NUM + BASE_NUM + FP_BASE_NUM) * RSIZE)=0D +=0D + st.d RA, SP, RA_NUM * RSIZE=0D + st.d GP, SP, GP_NUM * RSIZE=0D + st.d A0, SP, A0_NUM * RSIZE=0D + st.d A1, SP, A1_NUM * RSIZE=0D + st.d A2, SP, A2_NUM * RSIZE=0D + st.d A3, SP, A3_NUM * RSIZE=0D + st.d A4, SP, A4_NUM * RSIZE=0D + st.d A5, SP, A5_NUM * RSIZE=0D + st.d A6, SP, A6_NUM * RSIZE=0D + st.d A7, SP, A7_NUM * RSIZE=0D + st.d T1, SP, T1_NUM * RSIZE=0D + st.d T2, SP, T2_NUM * RSIZE=0D + st.d T3, SP, T3_NUM * RSIZE=0D + st.d T4, SP, T4_NUM * RSIZE=0D + st.d T5, SP, T5_NUM * RSIZE=0D + st.d T6, SP, T6_NUM * RSIZE=0D + st.d T7, SP, T7_NUM * RSIZE=0D + st.d T8, SP, T8_NUM * RSIZE=0D + st.d TP, SP, TP_NUM * RSIZE=0D + st.d FP, SP, FP_NUM * RSIZE=0D + st.d S0, SP, S0_NUM * RSIZE=0D + st.d S1, SP, S1_NUM * RSIZE=0D + st.d S2, SP, S2_NUM * RSIZE=0D + st.d S3, SP, S3_NUM * RSIZE=0D + st.d S4, SP, S4_NUM * RSIZE=0D + st.d S5, SP, S5_NUM * RSIZE=0D + st.d S6, SP, S6_NUM * RSIZE=0D + st.d S7, SP, S7_NUM * RSIZE=0D + st.d S8, SP, S8_NUM * RSIZE=0D +=0D + /*=0D + * save T0/SP from scratch registers on stack=0D + */=0D + csrrd T0, LOONGARCH_CSR_KS0=0D + st.d T0, SP, T0_NUM * RSIZE=0D + csrrd T0, LOONGARCH_CSR_KS1=0D + st.d T0, SP, SP_NUM * RSIZE=0D +=0D + csrrd T0, LOONGARCH_CSR_CRMD=0D + st.d T0, SP, (LOONGARCH_CSR_CRMD + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_PRMD=0D + st.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_ECFG=0D + st.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_ESTAT=0D + st.d T0, SP, (LOONGARCH_CSR_ESTAT + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_EPC=0D + st.d T0, SP, (LOONGARCH_CSR_EPC+ BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_BADV=0D + st.d T0, SP, (LOONGARCH_CSR_BADV + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_BADI=0D + st.d T0, SP, (LOONGARCH_CSR_BADI + BASE_NUM) * RSIZE=0D + csrrd T0, LOONGARCH_CSR_EUEN=0D + st.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE=0D +=0D + /* Save FPU context */=0D + ori T1, ZERO, CSR_EUEN_FPEN=0D + and T2, T0, T1=0D + beqz T2, 1f=0D +=0D + fst.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE=0D + fst.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE=0D +=0D + movfcsr2gr T3, FCSR0=0D + st.d T3, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE=0D + movcf2gr T3, $fcc0=0D + or T2, T3, ZERO=0D + movcf2gr T3, $fcc1=0D + bstrins.d T2, T3, 0xf, 0x8=0D + movcf2gr T3, $fcc2=0D + bstrins.d T2, T3, 0x17, 0x10=0D + movcf2gr T3, $fcc3=0D + bstrins.d T2, T3, 0x1f, 0x18=0D + movcf2gr T3, $fcc4=0D + bstrins.d T2, T3, 0x27, 0x20=0D + movcf2gr T3, $fcc5=0D + bstrins.d T2, T3, 0x2f, 0x28=0D + movcf2gr T3, $fcc6=0D + bstrins.d T2, T3, 0x37, 0x30=0D + movcf2gr T3, $fcc7=0D + bstrins.d T2, T3, 0x3f, 0x38=0D + st.d T2, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE=0D +1:=0D + or A0, SP, ZERO=0D + bl CommonExceptionEntry=0D + /*disable interrupt*/=0D + li.d T0, (1 << 2)=0D + csrxchg ZERO, T0, LOONGARCH_CSR_CRMD=0D +=0D + ld.d T0, SP, (LOONGARCH_CSR_PRMD + BASE_NUM) * RSIZE=0D + csrwr T0, LOONGARCH_CSR_PRMD=0D + ld.d T0, SP, (LOONGARCH_CSR_ECFG + BASE_NUM) * RSIZE=0D + csrwr T0, LOONGARCH_CSR_ECFG=0D + ld.d T0, SP, (LOONGARCH_CSR_EPC + BASE_NUM) * RSIZE=0D + csrwr T0, LOONGARCH_CSR_EPC=0D +=0D + ld.d T0, SP, (LOONGARCH_CSR_EUEN + BASE_NUM) * RSIZE=0D + ori T1, ZERO, CSR_EUEN_FPEN=0D + and T2, T0, T1=0D + beqz T2, 2f=0D +=0D + /*=0D + * check previous FP state=0D + * restore FP contect if FP enabled=0D + */=0D + fld.d $f0, SP, (FP0_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f1, SP, (FP1_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f2, SP, (FP2_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f3, SP, (FP3_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f4, SP, (FP4_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f5, SP, (FP5_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f6, SP, (FP6_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f7, SP, (FP7_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f8, SP, (FP8_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f9, SP, (FP9_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f10, SP, (FP10_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f11, SP, (FP11_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f12, SP, (FP12_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f13, SP, (FP13_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f14, SP, (FP14_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f15, SP, (FP15_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f16, SP, (FP16_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f17, SP, (FP17_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f18, SP, (FP18_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f19, SP, (FP19_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f20, SP, (FP20_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f21, SP, (FP21_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f22, SP, (FP22_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f23, SP, (FP23_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f24, SP, (FP24_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f25, SP, (FP25_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f26, SP, (FP26_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f27, SP, (FP27_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f28, SP, (FP28_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f29, SP, (FP29_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f30, SP, (FP30_NUM + FP_BASE_INDEX) * RSIZE=0D + fld.d $f31, SP, (FP31_NUM + FP_BASE_INDEX) * RSIZE=0D +=0D + ld.d T0, SP, (FCSR_NUM + FP_BASE_INDEX) * RSIZE=0D + movgr2fcsr FCSR0, T0=0D + ld.d T0, SP, (FCC_NUM + FP_BASE_INDEX) * RSIZE=0D + bstrpick.d T1, T0, 7, 0=0D + movgr2cf $fcc0, T1=0D + bstrpick.d T1, T0, 15, 8=0D + movgr2cf $fcc1, T1=0D + bstrpick.d T1, T0, 23, 16=0D + movgr2cf $fcc2, T1=0D + bstrpick.d T1, T0, 31, 24=0D + movgr2cf $fcc3, T1=0D + bstrpick.d T1, T0, 39, 32=0D + movgr2cf $fcc4, T1=0D + bstrpick.d T1, T0, 47, 40=0D + movgr2cf $fcc5, T1=0D + bstrpick.d T1, T0, 55, 48=0D + movgr2cf $fcc6, T1=0D + bstrpick.d T1, T0, 63, 56=0D + movgr2cf $fcc7, T1=0D +2:=0D + ld.d RA, SP, RA_NUM * RSIZE=0D + ld.d GP, SP, GP_NUM * RSIZE=0D + ld.d A0, SP, A0_NUM * RSIZE=0D + ld.d A1, SP, A1_NUM * RSIZE=0D + ld.d A2, SP, A2_NUM * RSIZE=0D + ld.d A3, SP, A3_NUM * RSIZE=0D + ld.d A4, SP, A4_NUM * RSIZE=0D + ld.d A5, SP, A5_NUM * RSIZE=0D + ld.d A6, SP, A6_NUM * RSIZE=0D + ld.d A7, SP, A7_NUM * RSIZE=0D + ld.d T0, SP, T0_NUM * RSIZE=0D + ld.d T1, SP, T1_NUM * RSIZE=0D + ld.d T2, SP, T2_NUM * RSIZE=0D + ld.d T3, SP, T3_NUM * RSIZE=0D + ld.d T4, SP, T4_NUM * RSIZE=0D + ld.d T5, SP, T5_NUM * RSIZE=0D + ld.d T6, SP, T6_NUM * RSIZE=0D + ld.d T7, SP, T7_NUM * RSIZE=0D + ld.d T8, SP, T8_NUM * RSIZE=0D + ld.d TP, SP, TP_NUM * RSIZE=0D + ld.d FP, SP, FP_NUM * RSIZE=0D + ld.d S0, SP, S0_NUM * RSIZE=0D + ld.d S1, SP, S1_NUM * RSIZE=0D + ld.d S2, SP, S2_NUM * RSIZE=0D + ld.d S3, SP, S3_NUM * RSIZE=0D + ld.d S4, SP, S4_NUM * RSIZE=0D + ld.d S5, SP, S5_NUM * RSIZE=0D + ld.d S6, SP, S6_NUM * RSIZE=0D + ld.d S7, SP, S7_NUM * RSIZE=0D + ld.d S8, SP, S8_NUM * RSIZE=0D +=0D + ld.d SP, SP, SP_NUM * RSIZE=0D + ertn=0D +=0D +/*=0D + Exception trampoline copied down to RAM after initialization.=0D + */=0D +ASM_FUNC(LoongArchException)=0D + csrwr T0, LOONGARCH_CSR_KS0=0D + csrwr SP, LOONGARCH_CSR_KS1=0D + pcaddi T0, 0=0D + ld.d T0, T0, 16=0D + jirl ZERO, T0, 0=0D + nop=0D +1:=0D + .quad Exception_handler=0D +.globl LoongArchExceptionEnd=0D +LoongArchExceptionEnd:=0D +=0D +/*=0D + Set Exception Base Address.=0D + */=0D +ASM_FUNC(SetEbase)=0D + /*=0D + * clear Vint cofigure=0D + * all exceptions share the same interrupt entry=0D + */=0D + csrrd T0, LOONGARCH_CSR_ECFG=0D + li.d T1, ~0x70000=0D + and T0, T0, T1=0D + csrwr T0, LOONGARCH_CSR_ECFG=0D +=0D + /*set ebase*/=0D + csrwr A0, LOONGARCH_CSR_EBASE=0D + jirl ZERO, RA, 0=0D --=20 2.31.1