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