From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id F209F940FF8 for ; Mon, 25 Mar 2024 02:35:12 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=WR/sdcRWyIFGv2mahdxNad1uC6cpuZ3Ur70dDU/paEI=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:msip_labels:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type; s=20240206; t=1711334111; v=1; b=YsygDN/LBosFhm7iP4ypkmeBtiyhiSS5gGdcy8H8Takbiw1XCKmGOKBgQlbjt0DN+3j01Rgb ZAwzDTRlMA6brbx0klEZ755A84gL4XgAV/lUv6mnya5UeFK4jzVaj6moZHUXM7jhJvgZMQfwHNv kwish0hfNT7vvlFzfOS8vHBA7rxcbbEtLm0lIJ+XOiCaNTCXzMtz/jIKOAZVR/dkMnR3Nfr2vw9 6I074FyWDTQfo8ZJlFos3dmXWx4w0tVM6Nw+xl0e8bbZtOD1IbaG5Z3OezklWE2FC9evbWoNo3P iivTCikGS90kfV0V+eu1xCuXV6yTH6J9dtTrrNu4mzndw== X-Received: by 127.0.0.2 with SMTP id yIHwYY7687511xhjXbRBROUv; Sun, 24 Mar 2024 19:35:11 -0700 X-Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.8]) by mx.groups.io with SMTP id smtpd.web11.43470.1711334110744712516 for ; Sun, 24 Mar 2024 19:35:10 -0700 X-IronPort-AV: E=McAfee;i="6600,9927,11023"; a="23803665" X-IronPort-AV: E=Sophos;i="6.07,152,1708416000"; d="scan'208,217";a="23803665" X-Received: from orviesa009.jf.intel.com ([10.64.159.149]) by fmvoesa102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 24 Mar 2024 19:35:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.07,152,1708416000"; d="scan'208,217";a="15450721" X-Received: from orsmsx603.amr.corp.intel.com ([10.22.229.16]) by orviesa009.jf.intel.com with ESMTP/TLS/AES256-GCM-SHA384; 24 Mar 2024 19:35:09 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX603.amr.corp.intel.com (10.22.229.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Sun, 24 Mar 2024 19:35:08 -0700 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Sun, 24 Mar 2024 19:35:08 -0700 X-Received: from ORSEDG601.ED.cps.intel.com (10.7.248.6) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend Transport; Sun, 24 Mar 2024 19:35:08 -0700 X-Received: from NAM04-MW2-obe.outbound.protection.outlook.com (104.47.73.168) by edgegateway.intel.com (134.134.137.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Sun, 24 Mar 2024 19:35:08 -0700 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com (2603:10b6:208:470::14) by SA2PR11MB4779.namprd11.prod.outlook.com (2603:10b6:806:11a::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.31; Mon, 25 Mar 2024 02:35:05 +0000 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::2c31:82b7:9f26:5817]) by MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::2c31:82b7:9f26:5817%5]) with mapi id 15.20.7409.028; Mon, 25 Mar 2024 02:35:04 +0000 From: "Ni, Ray" To: Chao Li , "devel@edk2.groups.io" CC: "Kumar, Rahul R" , Gerd Hoffmann , Baoqi Zhang , Dongyan Qian Subject: Re: [edk2-devel] [PATCH v2 13/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64 Thread-Topic: [PATCH v2 13/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64 Thread-Index: AQHaeqLQdo55qWC13EKDfUiMq1Wku7FHxHec Date: Mon, 25 Mar 2024 02:35:04 +0000 Message-ID: References: <20240320084152.268323-1-lichao@loongson.cn> <20240320084356.285693-1-lichao@loongson.cn> In-Reply-To: <20240320084356.285693-1-lichao@loongson.cn> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: MN6PR11MB8244:EE_|SA2PR11MB4779:EE_ x-ms-office365-filtering-correlation-id: c8aaae8f-9bb3-463c-815b-08dc4c742daa x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: H800o1GSqKV5zBypowPAgNZozhmDqdTzoU5FMLKe/GBqrDHS9fvSBhI9x9JRSSIbATWN8nFhy3BeOERR/AmSLGsbThXrg+ydHQlqhxdY5GQH5OOstzzNwZoun8ikU4XFL3yKw8FQZeHRl4mRYDMUzvwQF/OrrschK9RMLSy5I4jqqdcuwRiJQJUbItBCUUnJmSP7DuSui6QEwSo3abTYLiNiFy28S004dEqQ/2xnyHQGHn+7RDJ7ZkFzuY4qgmA5aBZmAUdQZkXJ3ta2u169HUMPdYP8vc/tHPvc5+arCcEaOl3d9DS7E4HUTtt599qnLMPmaR4rTA/7IY97NBX8aWqvujIe9EG9XX7H+fsbMrxX7y9bnSiT9IsfQf6c8ARKyBtcQWsbLDvMJqd+AeI5ut2SdVcKSAfPczfrN7Xx7uY4fvDWyprHoSYxt1cGs/CODIw4kL8O+SxQXmvPJ7X0HCV+/F3xANp2531ONv+FoA+O6JUp5jC5dTW8R8prDnlrPOibtnaTwPhg46BRW2yy+++vtiYJPcWtCkhb7GWDsaOReXSJY5ge38+f2KsyTgNJYVocbLu6EToBlQOvUgC6Ahdkx0wbwxwJ528UqeZnurlhj5V4vxTOeCzOjtU3ApXB6d282cKJ4+8fYBYcNBDdS+Lh78APmwNfp9ZtUEA44mM= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?MEkQI2mcbQUopkw21C2bZHe2usBdEfrTjpKN0G58MVhLpeq+NbAwVc1e2Nie?= =?us-ascii?Q?ceh+FPnUc4aizeRFit5SsI1s5Zxi17vsQ6zVMU+MNhQU6WlPvGycYBkr6N6W?= =?us-ascii?Q?8t9pXGerLSvhm0Wmm3BkGpN80WwBk8etpUQnpn8CB+BawfpFiL6ehwdUD48/?= =?us-ascii?Q?WfrS+T/OHzbE9lbfSQmgodzo46WRcE1JxGRnkAVB5wz6nBgy1p0XshK2rsZh?= =?us-ascii?Q?0emF/RyvkaZJ4lmPNUqM8oM0MTgfKRzFgH4fF1mMY77dbQCINoyXVW5GX5f7?= =?us-ascii?Q?i6qa8zc6lnjCdLxQ25mp6Ml0y8xwe1oEg0GjXHaVy+twSmGFmRKY+X4V6bLu?= =?us-ascii?Q?JtxDabQnCKmyOB1nhK7JIgJzGOP4NluH4hIK4S0zmJ1gjFvUine8DdWoeOqo?= =?us-ascii?Q?RqJ3gsTMj2XTm7Uk/ppLSsXjx29nQ4zx7E8Yuu9amQbDLf6SYX7qGcPGSYfK?= =?us-ascii?Q?Kjof5se1gPaG+EruJC0y2LK11sZL74hKf9bpx4QMkiONeuqeTXj1gOqq8f8Z?= =?us-ascii?Q?Djrr7aMwRFrtmC7Yw9qTxChj06i7tcIrpGVY1QQ67jmzeEhlm7JkgXHoxGFb?= =?us-ascii?Q?YabznywQAxsNyU2G6AOCG8haP1BxVigWKVsSDTfIPgYNgiCIBXZWz3GxLRGa?= =?us-ascii?Q?ImAzd5hOWejXT/q3pgEH79t9R6Pqpzgmlf4MgU2EjSaNX5Awypd5aOqz5Nb9?= =?us-ascii?Q?aZendV3y/bIYxfBalvCVJUoq1gTc2Yveu3AYOPFk3WKQZkQJ8vFE8bBnS4U4?= =?us-ascii?Q?sr/0WPRvUTTPuYWaBM0VT/pZ8ZeK1/UJsElwTG4gawNewWfsF9Nd0W18g3Jo?= =?us-ascii?Q?rge1bYS9R+4jyf0leBCvinHkHn6PeAILQbZuR3f206LKNS3GFpnc2vYgn7F+?= =?us-ascii?Q?BhHdGFSxtid7ht00G6fAfaajd9d4sEWpiZujJzExaCrg6l77rAILb4KcVNfa?= =?us-ascii?Q?iAsRMBLz23MXZmI/YrWm2Wfu9DlkhsbvwgpgbXn8Vo60Fcxcvv2/p9pVRFPM?= =?us-ascii?Q?tuKR1O/Ol1qFRlwhFy1aeaFqQPJptiu6KbpxOqOTHx6Zc3obNuGqtydWYsz5?= =?us-ascii?Q?nq9o8X/F25L1grPzyHx/S/pg0nJjbLRdx/7GSuAYb7+ioBkOhnXVeGBHBHuZ?= =?us-ascii?Q?w8xzlHrZ5cL7m1tK4FTTcRMt65+i77tyeR6G13V0/RZKjGwZD4aaGqPX5898?= =?us-ascii?Q?3kQpI/BAbx5vh0YBU4petEkyXWcr1mw1qHgwkmbzDaC6qAIFAvL+Y23OgsNd?= =?us-ascii?Q?7RE+mqpkbHMhKk/Y5dgFsgr8sGgVx3ifyVKY/ugeQPkAocb08Tp5Utu4KY1p?= =?us-ascii?Q?slFlXsF58RXLyyk9cNqw2ryIIW/XuLYZAY0YFueHDXrO9+9fKBGp3sSm4864?= =?us-ascii?Q?Hy80FCcW39KKGd+OfdYv4bk6STjqYx4DfPX8M3ucwxu2RVwuQkOKEs0PlHpl?= =?us-ascii?Q?Y6xYkEvYJ8sRbTmNgkAeT963AupG5jrCM6pUjGXJLz6Oqi7R8tDbFaqtuP03?= =?us-ascii?Q?v2NRvijw8BnEVFJAdUprg78vtekMvmqiWAxmveOsN+pBs0gAAELlXRS2UZTD?= =?us-ascii?Q?yDvmlOa4bbPva43Xlok=3D?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: MN6PR11MB8244.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: c8aaae8f-9bb3-463c-815b-08dc4c742daa X-MS-Exchange-CrossTenant-originalarrivaltime: 25 Mar 2024 02:35:04.5393 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: JiRV6+HfynUaIIMI7soiEPf7zmWUqgxo9mEqUycZu7TaHyDVSuFwS/RPqMr2nS4hieRmiU1en7du6DZOSbJLmQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA2PR11MB4779 X-OriginatorOrg: intel.com Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Sun, 24 Mar 2024 19:35:10 -0700 Reply-To: devel@edk2.groups.io,ray.ni@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: ffEALteA3H17B8zrZyNWejMOx7686176AA= Content-Language: en-US Content-Type: multipart/alternative; boundary="_000_MN6PR11MB8244A7C219BB6BFAD27AEF318C362MN6PR11MB8244namp_" X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b="YsygDN/L"; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=intel.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io --_000_MN6PR11MB8244A7C219BB6BFAD27AEF318C362MN6PR11MB8244namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Can you rename PcdCpuExceptionVectorBaseAddress to PcdLoongArch64ExceptionV= ectorBaseAddress and put the PCD definition/reference in the DEC/INF LoongA= rch64 section? Thanks, Ray ________________________________ From: Chao Li Sent: Wednesday, March 20, 2024 16:43 To: devel@edk2.groups.io Cc: Ni, Ray ; Kumar, Rahul R ; G= erd Hoffmann ; Baoqi Zhang ; Don= gyan Qian Subject: [PATCH v2 13/13] UefiCpuPkg: Add CpuDxe driver for LoongArch64 Added LoongArch64 CPU driver into CpuDxe. BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4734 Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Signed-off-by: Chao Li Co-authored-by: Baoqi Zhang Co-authored-by: Dongyan Qian --- UefiCpuPkg/CpuDxe/CpuDxe.inf | 23 +- UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c | 426 +++++++++++++++++ UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h | 288 ++++++++++++ UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c | 544 ++++++++++++++++++++++ UefiCpuPkg/CpuDxe/LoongArch64/Exception.c | 159 +++++++ 5 files changed, 1436 insertions(+), 4 deletions(-) create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf index 9e1c673283..50db9e8ed1 100644 --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf @@ -3,6 +3,7 @@ # # Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.
# Copyright (c) 2017, AMD Incorporated. All rights reserved.
+# Copyright (c) 2024, Loongson Technology Corporation Limited. All rights= reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -22,7 +23,7 @@ [Packages] MdeModulePkg/MdeModulePkg.dec UefiCpuPkg/UefiCpuPkg.dec -[LibraryClasses] +[LibraryClasses.common] BaseLib BaseMemoryLib CpuExceptionHandlerLib @@ -30,9 +31,7 @@ [LibraryClasses] DebugLib DxeServicesTableLib HobLib - LocalApicLib MemoryAllocationLib - MtrrLib MpInitLib PeCoffGetEntryPointLib ReportStatusCodeLib @@ -41,7 +40,15 @@ [LibraryClasses] UefiDriverEntryPoint UefiLib -[Sources] +[LibraryClasses.IA32, LibraryClasses.X64] + LocalApicLib + MtrrLib + +[LibraryClasses.LoongArch64] + CacheMaintenanceLib + CpuMmuLib + +[Sources.IA32, Sources.X64] CpuDxe.c CpuDxe.h CpuGdt.c @@ -59,6 +66,13 @@ [Sources.X64] X64/CpuAsm.nasm X64/PagingAttribute.c +[Sources.LoongArch64] + CpuMp.h + LoongArch64/CpuDxe.c + LoongArch64/CpuMp.c + LoongArch64/Exception.c + LoongArch64/CpuDxe.h + [Protocols] gEfiCpuArchProtocolGuid ## PRODUCES gEfiMpServiceProtocolGuid ## PRODUCES @@ -80,6 +94,7 @@ [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask ##= CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ##= CONSUMES gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ##= CONSUMES + gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress ##= CONSUMES [Depex] TRUE diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxe/Loo= ngArch64/CpuDxe.c new file mode 100644 index 0000000000..f7c34fdfee --- /dev/null +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c @@ -0,0 +1,426 @@ +/** @file CpuDxe.c + + CPU DXE Module to produce CPU ARCH Protocol. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "CpuDxe.h" +#include "CpuMp.h" +#include +#include +#include +#include + +UINT64 mTimerPeriod =3D 0; + +/** + IPI Interrupt Handler. + + @param InterruptType The type of interrupt that occurred + @param SystemContext A pointer to the system context when the interru= pt occurred +**/ +VOID +EFIAPI +IpiInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ); + +// +// Globals used to initialize the protocol +// +EFI_HANDLE mCpuHandle =3D NULL; +EFI_CPU_ARCH_PROTOCOL gCpu =3D { + CpuFlushCpuDataCache, + CpuEnableInterrupt, + CpuDisableInterrupt, + CpuGetInterruptState, + CpuInit, + CpuRegisterInterruptHandler, + CpuGetTimerValue, + CpuSetMemoryAttributes, + 0, // NumberOfTimers + 4, // DmaBufferAlignment +}; + +/** + 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_INVALID_PARAMETER The processor does not support the cache f= lush type specified + by FlushType. + +**/ +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)Leng= th); + 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 (); + + 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 (); + + 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 GetInterruptState (); + 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; +} + +/** + Registers a function to be called from the CPU interrupt handler. + + @param This Protocol instance structure + @param InterruptType Defines which interrupt to hook. IA-32 + valid range is 0x00 through 0xFF + @param InterruptHandler A pointer to a function of type + EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. A nul= l + pointer is an error condition. + + @retval EFI_SUCCESS If handler installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handl= er + for InterruptType was previously installe= d. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler f= or + InterruptType was not previously installe= d. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType + is not supported. + +**/ +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return RegisterInterruptHandler (InterruptType, InterruptHandler); +} + +/** + Returns a timer value from one of the CPU's internal timers. There is no + inherent time interval between ticks but is a function of the CPU 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 passe= s + 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 + ) +{ + UINT64 BeginValue; + UINT64 EndValue; + + if (TimerValue =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (TimerIndex !=3D 0) { + return EFI_INVALID_PARAMETER; + } + + *TimerValue =3D AsmReadStableCounter (); + + if (TimerPeriod !=3D NULL) { + if (mTimerPeriod =3D=3D 0) { + // + // Read time stamp counter before and after delay of 100 microsecond= s + // + BeginValue =3D AsmReadStableCounter (); + MicroSecondDelay (100); + EndValue =3D AsmReadStableCounter (); + // + // Calculate the actual frequency + // + mTimerPeriod =3D DivU64x64Remainder ( + MultU64x32 ( + 1000 * 1000 * 1000, + 100 + ), + EndValue - BeginValue, + NULL + ); + } + + *TimerPeriod =3D mTimerPeriod; + } + + return EFI_SUCCESS; +} + +/** + 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 EfiAttributes 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; + + Status =3D EFI_SUCCESS; + + if ((BaseAddress & (EFI_PAGE_SIZE - 1)) !=3D 0) { + // + // Minimum granularity is SIZE_4KB. + // + DEBUG (( + DEBUG_INFO, + "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum granularity is SIZE_= 4KB\n", + BaseAddress, + Length, + EfiAttributes + )); + + Status =3D EFI_UNSUPPORTED; + + return Status; + } + + Status =3D SetMemoryRegionAttributes (BaseAddress, Length, EfiAttributes= , 0x0); + + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + 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. + +**/ +VOID +EFIAPI +IdleLoopEventCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + CpuSleep (); +} + +/** + 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 +InitializeCpu ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT IdleLoopEvent; + + InitializeExceptions (&gCpu); + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &mCpuHandle, + &gEfiCpuArchProtocolGuid, + &gCpu, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gCpu.RegisterInterruptHandler ( + &gCpu, + EXCEPT_LOONGARCH_INT_IPI, + IpiInterruptHandler + ); + ASSERT_EFI_ERROR (Status); + + // + // Setup a callback for idle events + // + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + IdleLoopEventCallback, + NULL, + &gIdleLoopEventGuid, + &IdleLoopEvent + ); + ASSERT_EFI_ERROR (Status); + + InitializeMpSupport (); + + return Status; +} diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxe/Loo= ngArch64/CpuDxe.h new file mode 100644 index 0000000000..8bfbfa3442 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h @@ -0,0 +1,288 @@ +/** @file CpuDxe.c + + CPU DXE Module to produce CPU ARCH Protocol. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef CPU_DXE_H_ +#define CPU_DXE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// For coding convenience, define the maximum valid +// LoongArch exception. +// Since UEFI V2.11, it will be present in DebugSupport.h. +// +#define MAX_LOONGARCH_EXCEPTION 64 + +/* + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + 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 + ); + +/** + Registers a function to be called from the CPU interrupt handler. + + @param This Protocol instance structure + @param InterruptType Defines which interrupt to hook. IA-32 + valid range is 0x00 through 0xFF + @param InterruptHandler A pointer to a function of type + EFI_CPU_INTERRUPT_HANDLER that is called + when a processor interrupt occurs. A nul= l + pointer is an error condition. + + @retval EFI_SUCCESS If handler installed or uninstalled. + @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handl= er + for InterruptType was previously installe= d. + @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler f= or + InterruptType was not previously installe= d. + @retval EFI_UNSUPPORTED The interrupt specified by InterruptType + is not supported. + +**/ +EFI_STATUS +EFIAPI +CpuRegisterInterruptHandler ( + IN EFI_CPU_ARCH_PROTOCOL *This, + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +/** + 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 passe= s + 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 + ); + +/** + 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 A pointer to the processor's current interrupt = state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disable= d. + @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 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 +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ); + +/** + This function modifies the attributes for the memory region specified by= BaseAddress and + Length from their current attributes to the attributes specified by 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 + ); + +/** + Initialize interrupt handling for DXE phase. + + @param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance. + + @return VOID. + +**/ +VOID +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *gCpu + ); + +/** + Converts EFI Attributes to corresponding architecture Attributes. + + @param[in] EfiAttributes Efi Attributes. + + @retval Corresponding architecture attributes. +**/ +UINTN +EFIAPI +EfiAttributeConverse ( + IN UINTN EfiAttributes + ); + +#endif // CPU_DXE_H_ diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxe/Loon= gArch64/CpuMp.c new file mode 100644 index 0000000000..3325914e53 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c @@ -0,0 +1,544 @@ +/** @file + CPU DXE Module to produce CPU MP Protocol. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "CpuDxe.h" +#include "CpuMp.h" + +EFI_HANDLE mMpServiceHandle =3D NULL; +UINTN mNumberOfProcessors =3D 1; + +EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate =3D { + GetNumberOfProcessors, + GetProcessorInfo, + StartupAllAPs, + StartupThisAP, + SwitchBSP, + EnableDisableAP, + WhoAmI +}; + +/** + This service retrieves the number of logical processor in the platform + and the number of those logical processors that are enabled on this boot= . + This service may only be called from the BSP. + + This function is used to retrieve the following information: + - The number of logical processors that are present in the system. + - The number of enabled logical processors in the system at the instan= t + this call is made. + + Because MP Service Protocol provides services to enable and disable proc= essors + dynamically, the number of enabled logical processors may vary during th= e + course of a boot session. + + If this service is called from an AP, then EFI_DEVICE_ERROR is returned. + If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then + EFI_INVALID_PARAMETER is returned. Otherwise, the total number of proces= sors + is returned in NumberOfProcessors, the number of currently enabled proce= ssor + is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_MP_SERVICES= _PROTOCOL + instance. + @param[out] NumberOfProcessors Pointer to the total number of l= ogical + processors in the system, includ= ing the BSP + and disabled APs. + @param[out] NumberOfEnabledProcessors Pointer to the number of enabled= logical + processors that exist in system,= including + the BSP. + + @retval EFI_SUCCESS The number of logical processors and ena= bled + logical processors was retrieved. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. + @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL. + +**/ +EFI_STATUS +EFIAPI +GetNumberOfProcessors ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *NumberOfProcessors, + OUT UINTN *NumberOfEnabledProcessors + ) +{ + if ((NumberOfProcessors =3D=3D NULL) || (NumberOfEnabledProcessors =3D= =3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + return MpInitLibGetNumberOfProcessors ( + NumberOfProcessors, + NumberOfEnabledProcessors + ); +} + +/** + Gets detailed MP-related information on the requested processor at the + instant this call is made. This service may only be called from the BSP. + + This service retrieves detailed MP-related information about any process= or + on the platform. Note the following: + - The processor information may change during the course of a boot ses= sion. + - The information presented here is entirely MP related. + + Information regarding the number of caches and their sizes, frequency of= operation, + slot numbers is all considered platform-related information and is not p= rovided + by this service. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTO= COL + instance. + @param[in] ProcessorNumber The handle number of processor. + @param[out] ProcessorInfoBuffer A pointer to the buffer where informat= ion for + the requested processor is deposited. + + @retval EFI_SUCCESS Processor information was returned. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist in the pl= atform. + +**/ +EFI_STATUS +EFIAPI +GetProcessorInfo ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer + ) +{ + return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, = NULL); +} + +/** + This service executes a caller provided function on all enabled APs. APs= can + run either simultaneously or one at a time in sequence. This service sup= ports + both blocking and non-blocking requests. The non-blocking requests use E= FI + events so the BSP can detect when the APs have finished. This service ma= y only + be called from the BSP. + + This function is used to dispatch all the enabled APs to the function sp= ecified + by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned + immediately and Procedure is not started on any AP. + + If SingleThread is TRUE, all the enabled APs execute the function specif= ied by + Procedure one by one, in ascending order of processor handle number. Oth= erwise, + all the enabled APs execute the function specified by Procedure simultan= eously. + + If WaitEvent is NULL, execution is in blocking mode. The BSP waits until= all + APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in = non-blocking + mode, and the BSP returns from this service without waiting for APs. If = a + non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READ= Y_TO_BOOT + is signaled, then EFI_UNSUPPORTED must be returned. + + If the timeout specified by TimeoutInMicroseconds expires before all APs= return + from Procedure, then Procedure on the failed APs is terminated. All enab= led APs + are always available for further calls to EFI_MP_SERVICES_PROTOCOL.Start= upAllAPs() + and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NU= LL, its + content points to the list of processor handle numbers in which Procedur= e was + terminated. + + Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PR= OTOCOL.StartupAllAPs() + to make sure that the nature of the code that is executed on the BSP and= the + dispatched APs is well controlled. The MP Services Protocol does not gua= rantee + that the Procedure function is MP-safe. Hence, the tasks that can be run= in + parallel are limited to certain independent tasks and well-controlled ex= clusive + code. EFI services and protocols may not be called by APs unless otherwi= se + specified. + + In blocking execution mode, BSP waits until all APs finish or + TimeoutInMicroseconds expires. + + In non-blocking execution mode, BSP is freed to return to the caller and= then + proceed to the next task without having to wait for APs. The following + sequence needs to occur in a non-blocking execution mode: + + -# The caller that intends to use this MP Services Protocol in non-blo= cking + mode creates WaitEvent by calling the EFI CreateEvent() service. T= he caller + invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter = WaitEvent + is not NULL, then StartupAllAPs() executes in non-blocking mode. It= requests + the function specified by Procedure to be started on all the enable= d APs, + and releases the BSP to continue with other tasks. + -# The caller can use the CheckEvent() and WaitForEvent() services to = check + the state of the WaitEvent created in step 1. + -# When the APs complete their task or TimeoutInMicroSecondss expires,= the MP + Service signals WaitEvent by calling the EFI SignalEvent() function= . If + FailedCpuList is not NULL, its content is available when WaitEvent = is + signaled. If all APs returned from Procedure prior to the timeout, = then + FailedCpuList is set to NULL. If not all APs return from Procedure = before + the timeout, then FailedCpuList is filled in with the list of the f= ailed + APs. The buffer is allocated by MP Service Protocol using AllocateP= ool(). + It is the caller's responsibility to free the buffer with FreePool(= ) service. + -# This invocation of SignalEvent() function informs the caller that i= nvoked + EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs co= mpleted + the specified task or a timeout occurred. The contents of FailedCpu= List + can be examined to determine which APs did not complete the specifi= ed task + prior to the timeout. + + @param[in] This A pointer to the EFI_MP_SERVICES_PRO= TOCOL + instance. + @param[in] Procedure A pointer to the function to be run = on + enabled APs of the system. See type + EFI_AP_PROCEDURE. + @param[in] SingleThread If TRUE, then all the enabled APs ex= ecute + the function specified by Procedure = one by + one, in ascending order of processor= handle + number. If FALSE, then all the enab= led APs + execute the function specified by Pr= ocedure + simultaneously. + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until all A= Ps finish + or TimeoutInMicroseconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on all the e= nabled + APs, and go on executing immediately= . If + all return from Procedure, or Timeou= tInMicroseconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + APs to return from Procedure, either= for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + all APs return from Procedure, then = Procedure + on the failed APs is terminated. All= enabled + APs are available for next function = assigned + by EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupT= hisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = for + all APs. + @param[out] FailedCpuList If NULL, this parameter is ignored. = Otherwise, + if all APs finish successfully, then= its + content is set to NULL. If not all A= Ps + finish before timeout expires, then = its + content is set to address of the buf= fer + holding handle numbers of the failed= APs. + The buffer is allocated by MP Servic= e Protocol, + and it's the caller's responsibility= to + free the buffer with FreePool() serv= ice. + In blocking mode, it is ready for co= nsumption + when the call returns. In non-blocki= ng mode, + it is ready when WaitEvent is signal= ed. The + list of failed CPU is terminated by + END_OF_CPU_LIST. + + @retval EFI_SUCCESS In blocking mode, all APs have finished = before + the timeout expired. + @retval EFI_SUCCESS In non-blocking mode, function has been = dispatched + to all enabled APs. + @retval EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_DEVICE_ERROR Caller processor is AP. + @retval EFI_NOT_STARTED No enabled APs exist in the system. + @retval EFI_NOT_READY Any enabled APs are busy. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + all enabled APs have finished. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +StartupAllAPs ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN BOOLEAN SingleThread, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT UINTN **FailedCpuList OPTIONAL + ) +{ + return MpInitLibStartupAllAPs ( + Procedure, + SingleThread, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + FailedCpuList + ); +} + +/** + This service lets the caller get one enabled AP to execute a caller-prov= ided + function. The caller can request the BSP to either wait for the completi= on + of the AP or just proceed with the next task by using the EFI event mech= anism. + See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blo= cking + execution support. This service may only be called from the BSP. + + This function is used to dispatch one enabled AP to the function specifi= ed by + Procedure passing in the argument specified by ProcedureArgument. If Wa= itEvent + is NULL, execution is in blocking mode. The BSP waits until the AP finis= hes or + TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking = mode. + BSP proceeds to the next task without waiting for the AP. If a non-block= ing mode + is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signa= led, + then EFI_UNSUPPORTED must be returned. + + If the timeout specified by TimeoutInMicroseconds expires before the AP = returns + from Procedure, then execution of Procedure by the AP is terminated. The= AP is + available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs= () and + EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). + + @param[in] This A pointer to the EFI_MP_SERVICES_PRO= TOCOL + instance. + @param[in] Procedure A pointer to the function to be run = on the + designated AP of the system. See typ= e + EFI_AP_PROCEDURE. + @param[in] ProcessorNumber The handle number of the AP. The ran= ge is + from 0 to the total number of logica= l + processors minus 1. The total number= of + logical processors can be retrieved = by + EFI_MP_SERVICES_PROTOCOL.GetNumberOf= Processors(). + @param[in] WaitEvent The event created by the caller with= CreateEvent() + service. If it is NULL, then execut= e in + blocking mode. BSP waits until this = AP finish + or TimeoutInMicroSeconds expires. I= f it's + not NULL, then execute in non-blocki= ng mode. + BSP requests the function specified = by + Procedure to be started on this AP, + and go on executing immediately. If = this AP + return from Procedure or TimeoutInMi= croSeconds + expires, this event is signaled. The= BSP + can use the CheckEvent() or WaitForE= vent() + services to check the state of event= . Type + EFI_EVENT is defined in CreateEvent(= ) in + the Unified Extensible Firmware Inte= rface + Specification. + @param[in] TimeoutInMicroseconds Indicates the time limit in microsec= onds for + this AP to finish this Procedure, ei= ther for + blocking or non-blocking mode. Zero = means + infinity. If the timeout expires be= fore + this AP returns from Procedure, then= Procedure + on the AP is terminated. The + AP is available for next function as= signed + by EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs() + or EFI_MP_SERVICES_PROTOCOL.StartupT= hisAP(). + If the timeout expires in blocking m= ode, + BSP returns EFI_TIMEOUT. If the tim= eout + expires in non-blocking mode, WaitEv= ent + is signaled with SignalEvent(). + @param[in] ProcedureArgument The parameter passed into Procedure = on the + specified AP. + @param[out] Finished If NULL, this parameter is ignored. = In + blocking mode, this parameter is ign= ored. + In non-blocking mode, if AP returns = from + Procedure before the timeout expires= , its + content is set to TRUE. Otherwise, t= he + value is set to FALSE. The caller ca= n + determine if the AP returned from Pr= ocedure + by evaluating this value. + + @retval EFI_SUCCESS In blocking mode, specified AP finished = before + the timeout expires. + @retval EFI_SUCCESS In non-blocking mode, the function has b= een + dispatched to specified AP. + @retval EFI_UNSUPPORTED A non-blocking mode request was made aft= er the + UEFI event EFI_EVENT_GROUP_READY_TO_BOOT= was + signaled. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_TIMEOUT In blocking mode, the timeout expired be= fore + the specified AP has finished. + @retval EFI_NOT_READY The specified AP is busy. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or dis= abled AP. + @retval EFI_INVALID_PARAMETER Procedure is NULL. + +**/ +EFI_STATUS +EFIAPI +StartupThisAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN EFI_AP_PROCEDURE Procedure, + IN UINTN ProcessorNumber, + IN EFI_EVENT WaitEvent OPTIONAL, + IN UINTN TimeoutInMicroseconds, + IN VOID *ProcedureArgument OPTIONAL, + OUT BOOLEAN *Finished OPTIONAL + ) +{ + return MpInitLibStartupThisAP ( + Procedure, + ProcessorNumber, + WaitEvent, + TimeoutInMicroseconds, + ProcedureArgument, + Finished + ); +} + +/** + This service switches the requested AP to be the BSP from that point onw= ard. + This service changes the BSP for all purposes. This call can only be p= erformed + by the current BSP. + + This service switches the requested AP to be the BSP from that point onw= ard. + This service changes the BSP for all purposes. The new BSP can take over= the + execution of the old BSP and continue seamlessly from where the old one = left + off. This service may not be supported after the UEFI Event EFI_EVENT_GR= OUP_READY_TO_BOOT + is signaled. + + If the BSP cannot be switched prior to the return from this service, the= n + EFI_UNSUPPORTED must be returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL i= nstance. + @param[in] ProcessorNumber The handle number of AP that is to become t= he new + BSP. The range is from 0 to the total numbe= r of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors(). + @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as= an + enabled AP. Otherwise, it will be disabled. + + @retval EFI_SUCCESS BSP successfully switched. + @retval EFI_UNSUPPORTED Switching the BSP cannot be completed pr= ior to + this service returning. + @retval EFI_UNSUPPORTED Switching the BSP is not supported. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND The processor with the handle specified = by + ProcessorNumber does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BS= P or + a disabled AP. + @retval EFI_NOT_READY The specified AP is busy. + +**/ +EFI_STATUS +EFIAPI +SwitchBSP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableOldBSP + ) +{ + return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP); +} + +/** + This service lets the caller enable or disable an AP from this point onw= ard. + This service may only be called from the BSP. + + This service allows the caller enable or disable an AP from this point o= nward. + The caller can optionally specify the health status of the AP by Health.= If + an AP is being disabled, then the state of the disabled AP is implementa= tion + dependent. If an AP is enabled, then the implementation must guarantee t= hat a + complete initialization sequence is performed on the AP, so the AP is in= a state + that is compatible with an MP operating system. This service may not be = supported + after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled. + + If the enable or disable AP operation cannot be completed prior to the r= eturn + from this service, then EFI_UNSUPPORTED must be returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL i= nstance. + @param[in] ProcessorNumber The handle number of AP. + The range is from 0 to the total number of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors(). + @param[in] EnableAP Specifies the new state for the processor f= or + enabled, FALSE for disabled. + @param[in] HealthFlag If not NULL, a pointer to a value that spec= ifies + the new health status of the AP. This flag + corresponds to StatusFlag defined in + EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo()= . Only + the PROCESSOR_HEALTH_STATUS_BIT is used. Al= l other + bits are ignored. If it is NULL, this para= meter + is ignored. + + @retval EFI_SUCCESS The specified AP was enabled or disabled= successfully. + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be co= mpleted + prior to this service returning. + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not suppo= rted. + @retval EFI_DEVICE_ERROR The calling processor is an AP. + @retval EFI_NOT_FOUND Processor with the handle specified by P= rocessorNumber + does not exist. + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. + +**/ +EFI_STATUS +EFIAPI +EnableDisableAP ( + IN EFI_MP_SERVICES_PROTOCOL *This, + IN UINTN ProcessorNumber, + IN BOOLEAN EnableAP, + IN UINT32 *HealthFlag OPTIONAL + ) +{ + return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag); +} + +/** + This return the handle number for the calling processor. This service m= ay be + called from the BSP and APs. + + This service returns the processor handle number for the calling process= or. + The returned value is in the range from 0 to the total number of logical + processors minus 1. The total number of logical processors can be retrie= ved + with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may = be + called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALI= D_PARAMETER + is returned. Otherwise, the current processors handle number is returned= in + ProcessorNumber, and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL i= nstance. + @param[out] ProcessorNumber Pointer to the handle number of AP. + The range is from 0 to the total number of + logical processors minus 1. The total numbe= r of + logical processors can be retrieved by + EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors(). + + @retval EFI_SUCCESS The current processor handle number was = returned + in ProcessorNumber. + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. + +**/ +EFI_STATUS +EFIAPI +WhoAmI ( + IN EFI_MP_SERVICES_PROTOCOL *This, + OUT UINTN *ProcessorNumber + ) +{ + return MpInitLibWhoAmI (ProcessorNumber); +} + +/** + Initialize Multi-processor support. +**/ +VOID +InitializeMpSupport ( + VOID + ) +{ + EFI_STATUS Status; + UINTN NumberOfProcessors; + UINTN NumberOfEnabledProcessors; + + // + // Wakeup APs to do initialization + // + Status =3D MpInitLibInitialize (); + ASSERT_EFI_ERROR (Status); + + MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledPro= cessors); + mNumberOfProcessors =3D NumberOfProcessors; + DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors)); + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &mMpServiceHandle, + &gEfiMpServiceProtocolGuid, + &mMpServicesTemplate, + NULL + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuDxe/= LoongArch64/Exception.c new file mode 100644 index 0000000000..96def89936 --- /dev/null +++ b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c @@ -0,0 +1,159 @@ +/** @file Exception.c + + CPU DXE Module initialization exception instance. + + Copyright (c) 2024, Loongson Technology Corporation Limited. All rights = reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "CpuDxe.h" +#include +#include +#include + +VOID +ExceptionEntryStart ( + VOID + ); + +VOID +ExceptionEntryEnd ( + VOID + ); + +/** + 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 A pointer to the processor's current interrupt = state. Set to TRUE if interrupts + are enabled and FALSE if interrupts are disable= d. + @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 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 +RegisterInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler + ) +{ + return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, Interrupt= Handler); +} + +/** + Update the exception start entry code. + + @retval EFI_SUCCESS Update the exception start entry code down= . + @retval EFI_OUT_OF_RESOURCES The start entry code size out of bounds. + +**/ +EFI_STATUS +EFIAPI +UpdateExceptionStartEntry ( + VOID + ) +{ + EFI_PHYSICAL_ADDRESS ExceptionStartEntry; + UINTN VectorLength; + UINTN MaxLength; + UINTN MaxSizeOfVector; + + VectorLength =3D (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntryStart; + + // + // A vector is up to 512 bytes. + // + MaxSizeOfVector =3D 512; + MaxLength =3D (MAX_LOONGARCH_EXCEPTION + MAX_LOONGARCH_INTERRUPT) = * MaxSizeOfVector; + + if (VectorLength > MaxLength) { + return EFI_OUT_OF_RESOURCES; + } + + ExceptionStartEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress); + + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLeng= th); + CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, Vecto= rLength); + InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, VectorLeng= th); + InvalidateDataCache (); + + // + // If PcdCpuExceptionVectorBaseAddress is not used during SEC and PEI st= ages, the exception + // base addres is set to PcdCpuExceptionVectorBaseAddress. + // + if (CsrRead (LOONGARCH_CSR_EBASE) !=3D ExceptionStartEntry) { + SetExceptionBaseAddress (ExceptionStartEntry); + } + + return EFI_SUCCESS; +} + +/** + Initialize interrupt handling for DXE phase. + + @param Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance. + + @return VOID. + +**/ +VOID +InitializeExceptions ( + IN EFI_CPU_ARCH_PROTOCOL *Cpu + ) +{ + EFI_STATUS Status; + EFI_VECTOR_HANDOFF_INFO *VectorInfoList; + EFI_VECTOR_HANDOFF_INFO *VectorInfo; + BOOLEAN IrqEnabled; + + VectorInfo =3D (EFI_VECTOR_HANDOFF_INFO *)NULL; + Status =3D EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGu= id, (VOID **)&VectorInfoList); + + if ((Status =3D=3D EFI_SUCCESS) && (VectorInfoList !=3D NULL)) { + VectorInfo =3D VectorInfoList; + } + + // + // Disable interrupts + // + Cpu->GetInterruptState (Cpu, &IrqEnabled); + if (IrqEnabled) { + Cpu->DisableInterrupt (Cpu); + } + + // + // Update the Exception Start Entry code to point into CpuDxe. + // + Status =3D UpdateExceptionStartEntry (); + if (EFI_ERROR (Status)) { + DebugPrint (EFI_D_ERROR, "[%a]: Exception start entry code out of boun= ds!\n", __func__); + ASSERT_EFI_ERROR (Status); + } + + // + // Intialize the CpuExceptionHandlerLib so we take over the exception ve= ctor table from the DXE Core + // + Status =3D InitializeCpuExceptionHandlers (VectorInfo); + ASSERT_EFI_ERROR (Status); + + // + // Enable interrupts + // + DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled =3D %x\n", IrqE= nabled); + if (!IrqEnabled) { + Status =3D Cpu->EnableInterrupt (Cpu); + } + + ASSERT_EFI_ERROR (Status); +} -- 2.27.0 -=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 (#117076): https://edk2.groups.io/g/devel/message/117076 Mute This Topic: https://groups.io/mt/105041106/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --_000_MN6PR11MB8244A7C219BB6BFAD27AEF318C362MN6PR11MB8244namp_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable
Can you rename PcdCpuExceptionVectorBaseAd= dress to PcdLoongArch64ExceptionVectorBaseAddress and put the PCD d= efinition/reference in the DEC/INF LoongArch64 section?

Thanks,
Ray

From: Chao Li <lichao@lo= ongson.cn>
Sent: Wednesday, March 20, 2024 16:43
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: Ni, Ray <ray.ni@intel.com>; Kumar, Rahul R <rahul.r.kum= ar@intel.com>; Gerd Hoffmann <kraxel@redhat.com>; Baoqi Zhang <= zhangbaoqi@loongson.cn>; Dongyan Qian <qiandongyan@loongson.cn> Subject: [PATCH v2 13/13] UefiCpuPkg: Add CpuDxe driver for LoongArc= h64
 
Added LoongArch64 CPU driver into CpuDxe.

BZ: https= ://bugzilla.tianocore.org/show_bug.cgi?id=3D4734

Cc: Ray Ni <ray.ni@intel.com>
Cc: Rahul Kumar <rahul1.kumar@intel.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Chao Li <lichao@loongson.cn>
Co-authored-by: Baoqi Zhang <zhangbaoqi@loongson.cn>
Co-authored-by: Dongyan Qian <qiandongyan@loongson.cn>
---
 UefiCpuPkg/CpuDxe/CpuDxe.inf       = ;       |  23 +-
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c    | 426 ++++++= +++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h    | 288 ++++++= ++++++
 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c     | 544 += +++++++++++++++++++++
 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c | 159 +++++++
 5 files changed, 1436 insertions(+), 4 deletions(-)
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
 create mode 100644 UefiCpuPkg/CpuDxe/LoongArch64/Exception.c

diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf index 9e1c673283..50db9e8ed1 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -3,6 +3,7 @@
 #
 #  Copyright (c) 2008 - 2019, Intel Corporation. All rights rese= rved.<BR>
 #  Copyright (c) 2017, AMD Incorporated. All rights reserved.<= ;BR>
+#  Copyright (c) 2024, Loongson Technology Corporation Limited. All r= ights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -22,7 +23,7 @@ [Packages]
   MdeModulePkg/MdeModulePkg.dec
   UefiCpuPkg/UefiCpuPkg.dec
 
-[LibraryClasses]
+[LibraryClasses.common]
   BaseLib
   BaseMemoryLib
   CpuExceptionHandlerLib
@@ -30,9 +31,7 @@ [LibraryClasses]
   DebugLib
   DxeServicesTableLib
   HobLib
-  LocalApicLib
   MemoryAllocationLib
-  MtrrLib
   MpInitLib
   PeCoffGetEntryPointLib
   ReportStatusCodeLib
@@ -41,7 +40,15 @@ [LibraryClasses]
   UefiDriverEntryPoint
   UefiLib
 
-[Sources]
+[LibraryClasses.IA32, LibraryClasses.X64]
+  LocalApicLib
+  MtrrLib
+
+[LibraryClasses.LoongArch64]
+  CacheMaintenanceLib
+  CpuMmuLib
+
+[Sources.IA32, Sources.X64]
   CpuDxe.c
   CpuDxe.h
   CpuGdt.c
@@ -59,6 +66,13 @@ [Sources.X64]
   X64/CpuAsm.nasm
   X64/PagingAttribute.c
 
+[Sources.LoongArch64]
+  CpuMp.h
+  LoongArch64/CpuDxe.c
+  LoongArch64/CpuMp.c
+  LoongArch64/Exception.c
+  LoongArch64/CpuDxe.h
+
 [Protocols]
   gEfiCpuArchProtocolGuid      &nb= sp;            =     ## PRODUCES
   gEfiMpServiceProtocolGuid      &= nbsp;           &nbs= p;  ## PRODUCES
@@ -80,6 +94,7 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdTdxSharedBitMask  =             &nb= sp;     ## CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList =              ##= CONSUMES
   gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize  =             &nb= sp;     ## CONSUMES
+  gUefiCpuPkgTokenSpaceGuid.PcdCpuExceptionVectorBaseAddress &nb= sp;          ## CONSUMES
 
 [Depex]
   TRUE
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c b/UefiCpuPkg/CpuDxe/Loo= ngArch64/CpuDxe.c
new file mode 100644
index 0000000000..f7c34fdfee
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.c
@@ -0,0 +1,426 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All ri= ghts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+#include <Guid/IdleLoopEvent.h>
+#include <Library/CpuMmuLib.h>
+#include <Library/TimerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+UINT64  mTimerPeriod =3D 0;
+
+/**
+  IPI Interrupt Handler.
+
+  @param InterruptType    The type of interrupt that o= ccurred
+  @param SystemContext    A pointer to the system cont= ext when the interrupt occurred
+**/
+VOID
+EFIAPI
+IpiInterruptHandler (
+  IN EFI_EXCEPTION_TYPE  InterruptType,
+  IN EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+//
+// Globals used to initialize the protocol
+//
+EFI_HANDLE          &nbs= p;  mCpuHandle =3D NULL;
+EFI_CPU_ARCH_PROTOCOL  gCpu       =3D {=
+  CpuFlushCpuDataCache,
+  CpuEnableInterrupt,
+  CpuDisableInterrupt,
+  CpuGetInterruptState,
+  CpuInit,
+  CpuRegisterInterruptHandler,
+  CpuGetTimerValue,
+  CpuSetMemoryAttributes,
+  0,          // NumberO= fTimers
+  4,          // DmaBuff= erAlignment
+};
+
+/**
+  This function flushes the range of addresses from Start to Start+Le= ngth
+  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 b= oundary
+  are also flushed. If Start+Length is not aligned to a cache line bo= undary,
+  then the bytes past Start+Length to the end of the next cache line = boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalida= te must be
+  supported. If the data cache is fully coherent with all DMA operati= ons, then
+  this function can just return EFI_SUCCESS. If the processor does no= t support
+  flushing a range of the data cache, then the entire data cache can = be flushed.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start        &= nbsp;   The beginning physical address to flush from the processo= r's data
+            &n= bsp;            = ;  cache.
+  @param  Length        =    The number of bytes to flush from the processor's data cache. = This
+            &n= bsp;            = ;  function may flush more bytes than Length specifies depending upon<= br> +            &n= bsp;            = ;  the granularity of the flush operation that the processor supports.=
+  @param  FlushType        Sp= ecifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS        =    The address range from Start to Start+Length was flushed from<= br> +            &n= bsp;            = ;       the processor's data cache.
+  @retval EFI_INVALID_PARAMETER The processor does not support the ca= che flush type specified
+            &n= bsp;            = ;       by FlushType.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64         &nbs= p;       Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  )
+{
+  switch (FlushType) {
+    case EfiCpuFlushTypeWriteBack:
+      WriteBackDataCacheRange ((VOID *)(UINTN)Sta= rt, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeInvalidate:
+      InvalidateDataCacheRange ((VOID *)(UINTN)St= art, (UINTN)Length);
+      break;
+    case EfiCpuFlushTypeWriteBackInvalidate:
+      WriteBackInvalidateDataCacheRange ((VOID *)= (UINTN)Start, (UINTN)Length);
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS        =    Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts c= ould not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  EnableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS        =    Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts c= ould not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  )
+{
+  DisableInterrupts ();
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves the processor's current interrupt state a r= eturns it in
+  State. If interrupts are currently enabled, then TRUE is returned. = If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State        &= nbsp;   A pointer to the processor's current interrupt state. Set= to TRUE if
+            &n= bsp;            = ;  interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS        =    The processor's current interrupt state was returned in State.=
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN         &n= bsp;      *State
+  )
+{
+  if (State =3D=3D NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *State =3D GetInterruptState ();
+  return EFI_SUCCESS;
+}
+
+/**
+  This function generates an INIT on the processor. If this function = succeeds, then the
+  processor will be reset, and control will not be returned to the ca= ller. If InitType is
+  not supported by this processor, or the processor cannot programmat= ically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is r= eturned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is ret= urned.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType       &nbs= p; The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS        =    The processor INIT was performed. This return code should neve= r be seen.
+  @retval EFI_UNSUPPORTED       The pro= cessor INIT operation specified by InitType is not supported
+            &n= bsp;            = ;       by this processor.
+  @retval EFI_DEVICE_ERROR      The processo= r INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Registers a function to be called from the CPU interrupt handler. +
+  @param  This        &n= bsp;          Protocol instanc= e structure
+  @param  InterruptType       = ;   Defines which interrupt to hook. IA-32
+            &n= bsp;            = ;        valid range is 0x00 through 0xF= F
+  @param  InterruptHandler       A= pointer to a function of type
+            &n= bsp;            = ;        EFI_CPU_INTERRUPT_HANDLER that = is called
+            &n= bsp;            = ;        when a processor interrupt occu= rs.  A null
+            &n= bsp;            = ;        pointer is an error condition.<= br> +
+  @retval EFI_SUCCESS        =     If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is n= ot NULL, and a handler
+            &n= bsp;            = ;        for InterruptType was previousl= y installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a= handler for
+            &n= bsp;            = ;        InterruptType was not previousl= y installed.
+  @retval EFI_UNSUPPORTED        T= he interrupt specified by InterruptType
+            &n= bsp;            = ;        is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE       &nbs= p; InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return RegisterInterruptHandler (InterruptType, InterruptHandler);<= br> +}
+
+/**
+  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 f= requency.
+
+  @param  This        &n= bsp;       - Protocol instance structure.
+  @param  TimerIndex       &n= bsp;  - Specifies which CPU timer is requested.
+  @param  TimerValue       &n= bsp;  - Pointer to the returned timer value.
+  @param  TimerPeriod       &= nbsp; - A pointer to the amount of time that passes
+            &n= bsp;            = ;       in femtoseconds (10-15) for each incr= ement
+            &n= bsp;            = ;       of TimerValue. If TimerValue does not=
+            &n= bsp;            = ;       increment at a predictable rate, then= 0 is
+            &n= bsp;            = ;       returned.  The amount of time th= at has
+            &n= bsp;            = ;       passed between two calls to GetTimerV= alue()
+            &n= bsp;            = ;       can be calculated with the formula +            &n= bsp;            = ;       (TimerValue2 - TimerValue1) * TimerPe= riod.
+            &n= bsp;            = ;       This parameter is optional and may be= NULL.
+
+  @retval EFI_SUCCESS        =    - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If th= e CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an erro= r occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerVal= ue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32        &nbs= p;        TimerIndex,
+  OUT UINT64         &nb= sp;       *TimerValue,
+  OUT UINT64         &nb= sp;       *TimerPeriod   OPTIONAL +  )
+{
+  UINT64  BeginValue;
+  UINT64  EndValue;
+
+  if (TimerValue =3D=3D NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (TimerIndex !=3D 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *TimerValue =3D AsmReadStableCounter ();
+
+  if (TimerPeriod !=3D NULL) {
+    if (mTimerPeriod =3D=3D 0) {
+      //
+      // Read time stamp counter before and after= delay of 100 microseconds
+      //
+      BeginValue =3D AsmReadStableCounter ();
+      MicroSecondDelay (100);
+      EndValue =3D AsmReadStableCounter ();
+      //
+      // Calculate the actual frequency
+      //
+      mTimerPeriod =3D DivU64x64Remainder (
+            &n= bsp;          MultU64x32 (
+            &n= bsp;            1000= * 1000 * 1000,
+            &n= bsp;            100<= br> +            &n= bsp;            ), +            &n= bsp;          EndValue - Begin= Value,
+            &n= bsp;          NULL
+            &n= bsp;          );
+    }
+
+    *TimerPeriod =3D mTimerPeriod;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function modifies the attributes for the memory region specifi= ed by BaseAddress and
+  Length from their current attributes to the attributes specified by= Attributes.
+
+  @param  This        &n= bsp;    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  EfiAttributes    The bit mask of attrib= utes to set for the memory region.
+
+  @retval EFI_SUCCESS        =    The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes fo= r the memory resource range specified by
+            &n= bsp;            = ;       BaseAddress and Length cannot be modi= fied.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system reso= urces to modify the attributes of
+            &n= bsp;            = ;       the memory resource range.
+  @retval EFI_UNSUPPORTED       The pro= cessor does not support one or more bytes of the memory
+            &n= bsp;            = ;       resource range specified by BaseAddre= ss and Length.
+            &n= bsp;            = ;       The bit mask of attributes is not sup= port for the memory resource
+            &n= bsp;            = ;       range specified by BaseAddress and Le= ngth.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64         &nbs= p;       Length,
+  IN UINT64         &nbs= p;       EfiAttributes
+  )
+{
+  EFI_STATUS  Status;
+
+  Status =3D EFI_SUCCESS;
+
+  if ((BaseAddress & (EFI_PAGE_SIZE - 1)) !=3D 0) {
+    //
+    // Minimum granularity is SIZE_4KB.
+    //
+    DEBUG ((
+      DEBUG_INFO,
+      "CpuSetMemoryAttributes(%lx, %lx, %lx)= : Minimum granularity is SIZE_4KB\n",
+      BaseAddress,
+      Length,
+      EfiAttributes
+      ));
+
+    Status =3D EFI_UNSUPPORTED;
+
+    return Status;
+  }
+
+  Status =3D SetMemoryRegionAttributes (BaseAddress, Length, EfiAttri= butes, 0x0);
+
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Callback function for idle events.
+
+  @param  Event        &= nbsp;        Event whose notification fu= nction is being invoked.
+  @param  Context        = ;       The pointer to the notification funct= ion's context,
+            &n= bsp;            = ;       which is implementation-dependent. +
+**/
+VOID
+EFIAPI
+IdleLoopEventCallback (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  CpuSleep ();
+}
+
+/**
+  Initialize the state information for the CPU Architectural Protocol= .
+
+  @param ImageHandle     Image handle this driver= .
+  @param SystemTable     Pointer to the System Ta= ble.
+
+  @retval EFI_SUCCESS        =    Thread can be successfully created
+  @retval EFI_OUT_OF_RESOURCES  Cannot allocate protocol data st= ructure
+  @retval EFI_DEVICE_ERROR      Cannot creat= e the thread
+
+**/
+EFI_STATUS
+InitializeCpu (
+  IN EFI_HANDLE        ImageHandle= ,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_EVENT   IdleLoopEvent;
+
+  InitializeExceptions (&gCpu);
+
+  Status =3D gBS->InstallMultipleProtocolInterfaces (
+            &n= bsp;     &mCpuHandle,
+            &n= bsp;     &gEfiCpuArchProtocolGuid,
+            &n= bsp;     &gCpu,
+            &n= bsp;     NULL
+            &n= bsp;     );
+  ASSERT_EFI_ERROR (Status);
+
+  Status =3D gCpu.RegisterInterruptHandler (
+            &n= bsp;     &gCpu,
+            &n= bsp;     EXCEPT_LOONGARCH_INT_IPI,
+            &n= bsp;     IpiInterruptHandler
+            &n= bsp;     );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Setup a callback for idle events
+  //
+  Status =3D gBS->CreateEventEx (
+            &n= bsp;     EVT_NOTIFY_SIGNAL,
+            &n= bsp;     TPL_NOTIFY,
+            &n= bsp;     IdleLoopEventCallback,
+            &n= bsp;     NULL,
+            &n= bsp;     &gIdleLoopEventGuid,
+            &n= bsp;     &IdleLoopEvent
+            &n= bsp;     );
+  ASSERT_EFI_ERROR (Status);
+
+  InitializeMpSupport ();
+
+  return Status;
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h b/UefiCpuPkg/CpuDxe/Loo= ngArch64/CpuDxe.h
new file mode 100644
index 0000000000..8bfbfa3442
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuDxe.h
@@ -0,0 +1,288 @@
+/** @file CpuDxe.c
+
+  CPU DXE Module to produce CPU ARCH Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All ri= ghts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef CPU_DXE_H_
+#define CPU_DXE_H_
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Guid/DebugImageInfoTable.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/LoadedImage.h>
+
+//
+// For coding convenience, define the maximum valid
+// LoongArch exception.
+// Since UEFI V2.11, it will be present in DebugSupport.h.
+//
+#define MAX_LOONGARCH_EXCEPTION  64
+
+/*
+  This function flushes the range of addresses from Start to Start+Le= ngth
+  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 b= oundary
+  are also flushed. If Start+Length is not aligned to a cache line bo= undary,
+  then the bytes past Start+Length to the end of the next cache line = boundary
+  are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalida= te must be
+  supported. If the data cache is fully coherent with all DMA operati= ons, then
+  this function can just return EFI_SUCCESS. If the processor does no= t support
+  flushing a range of the data cache, then the entire data cache can = be flushed.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  Start        &= nbsp;   The beginning physical address to flush from the processo= r's data
+            &n= bsp;            = ;  cache.
+  @param  Length        =    The number of bytes to flush from the processor's data cache. = This
+            &n= bsp;            = ;  function may flush more bytes than Length specifies depending upon<= br> +            &n= bsp;            = ;  the granularity of the flush operation that the processor supports.=
+  @param  FlushType        Sp= ecifies the type of flush operation to perform.
+
+  @retval EFI_SUCCESS        =    The address range from Start to Start+Length was flushed from<= br> +            &n= bsp;            = ;       the processor's data cache.
+  @retval EFI_UNSUPPORTEDT      The processo= r does not support the cache flush type specified
+            &n= bsp;            = ;       by FlushType.
+  @retval EFI_DEVICE_ERROR      The address = range from Start to Start+Length could not be flushed
+            &n= bsp;            = ;       from the processor's data cache.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuFlushCpuDataCache (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   Start,
+  IN UINT64         &nbs= p;       Length,
+  IN EFI_CPU_FLUSH_TYPE     FlushType
+  );
+
+/**
+  This function enables interrupt processing by the processor.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS        =    Interrupts are enabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts c= ould not be enabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuEnableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function disables interrupt processing by the processor.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+
+  @retval EFI_SUCCESS        =    Interrupts are disabled on the processor.
+  @retval EFI_DEVICE_ERROR      Interrupts c= ould not be disabled on the processor.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuDisableInterrupt (
+  IN EFI_CPU_ARCH_PROTOCOL  *This
+  );
+
+/**
+  This function retrieves the processor's current interrupt state a r= eturns it in
+  State. If interrupts are currently enabled, then TRUE is returned. = If interrupts
+  are currently disabled, then FALSE is returned.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  State        &= nbsp;   A pointer to the processor's current interrupt state. Set= to TRUE if
+            &n= bsp;            = ;  interrupts are enabled and FALSE if interrupts are disabled.
+
+  @retval EFI_SUCCESS        =    The processor's current interrupt state was returned in State.=
+  @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  OUT BOOLEAN         &n= bsp;      *State
+  );
+
+/**
+  This function generates an INIT on the processor. If this function = succeeds, then the
+  processor will be reset, and control will not be returned to the ca= ller. If InitType is
+  not supported by this processor, or the processor cannot programmat= ically generate an
+  INIT without help from external hardware, then EFI_UNSUPPORTED is r= eturned. If an error
+  occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is ret= urned.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  InitType       &nbs= p; The type of processor INIT to perform.
+
+  @retval EFI_SUCCESS        =    The processor INIT was performed. This return code should neve= r be seen.
+  @retval EFI_UNSUPPORTED       The pro= cessor INIT operation specified by InitType is not supported
+            &n= bsp;            = ;       by this processor.
+  @retval EFI_DEVICE_ERROR      The processo= r INIT failed.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuInit (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_CPU_INIT_TYPE      InitType
+  );
+
+/**
+  Registers a function to be called from the CPU interrupt handler. +
+  @param  This        &n= bsp;          Protocol instanc= e structure
+  @param  InterruptType       = ;   Defines which interrupt to hook. IA-32
+            &n= bsp;            = ;        valid range is 0x00 through 0xF= F
+  @param  InterruptHandler       A= pointer to a function of type
+            &n= bsp;            = ;        EFI_CPU_INTERRUPT_HANDLER that = is called
+            &n= bsp;            = ;        when a processor interrupt occu= rs.  A null
+            &n= bsp;            = ;        pointer is an error condition.<= br> +
+  @retval EFI_SUCCESS        =     If handler installed or uninstalled.
+  @retval EFI_ALREADY_STARTED    InterruptHandler is n= ot NULL, and a handler
+            &n= bsp;            = ;        for InterruptType was previousl= y installed.
+  @retval EFI_INVALID_PARAMETER  InterruptHandler is NULL, and a= handler for
+            &n= bsp;            = ;        InterruptType was not previousl= y installed.
+  @retval EFI_UNSUPPORTED        T= he interrupt specified by InterruptType
+            &n= bsp;            = ;        is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuRegisterInterruptHandler (
+  IN EFI_CPU_ARCH_PROTOCOL      *This,
+  IN EFI_EXCEPTION_TYPE       &nbs= p; InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  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 f= requency.
+
+  @param  This        &n= bsp;       - Protocol instance structure.
+  @param  TimerIndex       &n= bsp;  - Specifies which CPU timer is requested.
+  @param  TimerValue       &n= bsp;  - Pointer to the returned timer value.
+  @param  TimerPeriod       &= nbsp; - A pointer to the amount of time that passes
+            &n= bsp;            = ;       in femtoseconds (10-15) for each incr= ement
+            &n= bsp;            = ;       of TimerValue. If TimerValue does not=
+            &n= bsp;            = ;       increment at a predictable rate, then= 0 is
+            &n= bsp;            = ;       returned.  The amount of time th= at has
+            &n= bsp;            = ;       passed between two calls to GetTimerV= alue()
+            &n= bsp;            = ;       can be calculated with the formula +            &n= bsp;            = ;       (TimerValue2 - TimerValue1) * TimerPe= riod.
+            &n= bsp;            = ;       This parameter is optional and may be= NULL.
+
+  @retval EFI_SUCCESS        =    - If the CPU timer count was returned.
+  @retval EFI_UNSUPPORTED       - If th= e CPU does not have any readable timers.
+  @retval EFI_DEVICE_ERROR      - If an erro= r occurred while reading the timer.
+  @retval EFI_INVALID_PARAMETER - TimerIndex is not valid or TimerVal= ue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetTimerValue (
+  IN  EFI_CPU_ARCH_PROTOCOL  *This,
+  IN  UINT32        &nbs= p;        TimerIndex,
+  OUT UINT64         &nb= sp;       *TimerValue,
+  OUT UINT64         &nb= sp;       *TimerPeriod   OPTIONAL +  );
+
+/**
+  This function registers and enables the handler specified by Interr= uptHandler for a processor
+  interrupt or exception type specified by InterruptType. If Interrup= tHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by = InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt o= r exception.
+
+  @param  InterruptType    A pointer to the proce= ssor's current interrupt state. Set to TRUE if interrupts
+            &n= bsp;            = ;  are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_C= PU_INTERRUPT_HANDLER that is called
+            &n= bsp;            = ;  when a processor interrupt occurs. If this parameter is NULL, then = the handler
+            &n= bsp;            = ;  will be uninstalled.
+
+  @retval EFI_SUCCESS        =    The handler for the processor interrupt was successfully insta= lled or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NUL= L, and a handler for InterruptType was
+            &n= bsp;            = ;       previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handl= er for InterruptType was not
+            &n= bsp;            = ;       previously installed.
+  @retval EFI_UNSUPPORTED       The int= errupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE       &nbs= p; InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  );
+
+/**
+  This function modifies the attributes for the memory region specifi= ed by BaseAddress and
+  Length from their current attributes to the attributes specified by= Attributes.
+
+  @param  This        &n= bsp;    The EFI_CPU_ARCH_PROTOCOL instance.
+  @param  BaseAddress      The physical= address that is the start address of a memory region.
+  @param  Length        =    The size in bytes of the memory region.
+  @param  Attributes       The bit= mask of attributes to set for the memory region.
+
+  @retval EFI_SUCCESS        =    The attributes were set for the memory region.
+  @retval EFI_ACCESS_DENIED     The attributes fo= r the memory resource range specified by
+            &n= bsp;            = ;       BaseAddress and Length cannot be modi= fied.
+  @retval EFI_INVALID_PARAMETER Length is zero.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough system reso= urces to modify the attributes of
+            &n= bsp;            = ;       the memory resource range.
+  @retval EFI_UNSUPPORTED       The pro= cessor does not support one or more bytes of the memory
+            &n= bsp;            = ;       resource range specified by BaseAddre= ss and Length.
+            &n= bsp;            = ;       The bit mask of attributes is not sup= port for the memory resource
+            &n= bsp;            = ;       range specified by BaseAddress and Le= ngth.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+  IN EFI_CPU_ARCH_PROTOCOL  *This,
+  IN EFI_PHYSICAL_ADDRESS   BaseAddress,
+  IN UINT64         &nbs= p;       Length,
+  IN UINT64         &nbs= p;       Attributes
+  );
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *gCpu
+  );
+
+/**
+  Converts EFI Attributes to corresponding architecture Attributes. +
+  @param[in]  EfiAttributes     Efi Attribut= es.
+
+  @retval  Corresponding architecture attributes.
+**/
+UINTN
+EFIAPI
+EfiAttributeConverse (
+  IN UINTN  EfiAttributes
+  );
+
+#endif // CPU_DXE_H_
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c b/UefiCpuPkg/CpuDxe/Loon= gArch64/CpuMp.c
new file mode 100644
index 0000000000..3325914e53
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/CpuMp.c
@@ -0,0 +1,544 @@
+/** @file
+  CPU DXE Module to produce CPU MP Protocol.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All ri= ghts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include "CpuMp.h"
+
+EFI_HANDLE  mMpServiceHandle    =3D NULL;
+UINTN       mNumberOfProcessors =3D 1;
+
+EFI_MP_SERVICES_PROTOCOL  mMpServicesTemplate =3D {
+  GetNumberOfProcessors,
+  GetProcessorInfo,
+  StartupAllAPs,
+  StartupThisAP,
+  SwitchBSP,
+  EnableDisableAP,
+  WhoAmI
+};
+
+/**
+  This service retrieves the number of logical processor in the platf= orm
+  and the number of those logical processors that are enabled on this= boot.
+  This service may only be called from the BSP.
+
+  This function is used to retrieve the following information:
+    - The number of logical processors that are present in = the system.
+    - The number of enabled logical processors in the syste= m at the instant
+      this call is made.
+
+  Because MP Service Protocol provides services to enable and disable= processors
+  dynamically, the number of enabled logical processors may vary duri= ng the
+  course of a boot session.
+
+  If this service is called from an AP, then EFI_DEVICE_ERROR is retu= rned.
+  If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then +  EFI_INVALID_PARAMETER is returned. Otherwise, the total number of p= rocessors
+  is returned in NumberOfProcessors, the number of currently enabled = processor
+  is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is return= ed.
+
+  @param[in]  This       &nbs= p;            &= nbsp;   A pointer to the EFI_MP_SERVICES_PROTOCOL
+            &n= bsp;            = ;            &n= bsp;    instance.
+  @param[out] NumberOfProcessors      &= nbsp;   Pointer to the total number of logical
+            &n= bsp;            = ;            &n= bsp;    processors in the system, including the BSP
+            &n= bsp;            = ;            &n= bsp;    and disabled APs.
+  @param[out] NumberOfEnabledProcessors   Pointer to the nu= mber of enabled logical
+            &n= bsp;            = ;            &n= bsp;    processors that exist in system, including
+            &n= bsp;            = ;            &n= bsp;    the BSP.
+
+  @retval EFI_SUCCESS        =      The number of logical processors and enabled
+            &n= bsp;            = ;         logical processors was re= trieved.
+  @retval EFI_DEVICE_ERROR        = The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   NumberOfProcessors is NUL= L.
+  @retval EFI_INVALID_PARAMETER   NumberOfEnabledProcessors= is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN         &nbs= p;           *NumberOfPro= cessors,
+  OUT UINTN         &nbs= p;           *NumberOfEna= bledProcessors
+  )
+{
+  if ((NumberOfProcessors =3D=3D NULL) || (NumberOfEnabledProcessors = =3D=3D NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return MpInitLibGetNumberOfProcessors (
+           NumberOfProce= ssors,
+           NumberOfEnabl= edProcessors
+           );
+}
+
+/**
+  Gets detailed MP-related information on the requested processor at = the
+  instant this call is made. This service may only be called from the= BSP.
+
+  This service retrieves detailed MP-related information about any pr= ocessor
+  on the platform. Note the following:
+    - The processor information may change during the cours= e of a boot session.
+    - The information presented here is entirely MP related= .
+
+  Information regarding the number of caches and their sizes, frequen= cy of operation,
+  slot numbers is all considered platform-related information and is = not provided
+  by this service.
+
+  @param[in]  This       &nbs= p;          A pointer to the E= FI_MP_SERVICES_PROTOCOL
+            &n= bsp;            = ;           instance.
+  @param[in]  ProcessorNumber      = ; The handle number of processor.
+  @param[out] ProcessorInfoBuffer   A pointer to the buffer= where information for
+            &n= bsp;            = ;           the requested= processor is deposited.
+
+  @retval EFI_SUCCESS        =      Processor information was returned.
+  @retval EFI_DEVICE_ERROR        = The calling processor is an AP.
+  @retval EFI_INVALID_PARAMETER   ProcessorInfoBuffer is NU= LL.
+  @retval EFI_NOT_FOUND       &nbs= p;   The processor with the handle specified by
+            &n= bsp;            = ;         ProcessorNumber does not = exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,
+  IN  UINTN         = ;             P= rocessorNumber,
+  OUT EFI_PROCESSOR_INFORMATION  *ProcessorInfoBuffer
+  )
+{
+  return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuf= fer, NULL);
+}
+
+/**
+  This service executes a caller provided function on all enabled APs= . APs can
+  run either simultaneously or one at a time in sequence. This servic= e supports
+  both blocking and non-blocking requests. The non-blocking requests = use EFI
+  events so the BSP can detect when the APs have finished. This servi= ce may only
+  be called from the BSP.
+
+  This function is used to dispatch all the enabled APs to the functi= on specified
+  by Procedure.  If any enabled AP is busy, then EFI_NOT_READY i= s returned
+  immediately and Procedure is not started on any AP.
+
+  If SingleThread is TRUE, all the enabled APs execute the function s= pecified by
+  Procedure one by one, in ascending order of processor handle number= . Otherwise,
+  all the enabled APs execute the function specified by Procedure sim= ultaneously.
+
+  If WaitEvent is NULL, execution is in blocking mode. The BSP waits = until all
+  APs finish or TimeoutInMicroseconds expires. Otherwise, execution i= s in non-blocking
+  mode, and the BSP returns from this service without waiting for APs= . If a
+  non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP= _READY_TO_BOOT
+  is signaled, then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before al= l APs return
+  from Procedure, then Procedure on the failed APs is terminated. All= enabled APs
+  are always available for further calls to EFI_MP_SERVICES_PROTOCOL.= StartupAllAPs()
+  and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is n= ot NULL, its
+  content points to the list of processor handle numbers in which Pro= cedure was
+  terminated.
+
+  Note: It is the responsibility of the consumer of the EFI_MP_SERVIC= ES_PROTOCOL.StartupAllAPs()
+  to make sure that the nature of the code that is executed on the BS= P and the
+  dispatched APs is well controlled. The MP Services Protocol does no= t guarantee
+  that the Procedure function is MP-safe. Hence, the tasks that can b= e run in
+  parallel are limited to certain independent tasks and well-controll= ed exclusive
+  code. EFI services and protocols may not be called by APs unless ot= herwise
+  specified.
+
+  In blocking execution mode, BSP waits until all APs finish or
+  TimeoutInMicroseconds expires.
+
+  In non-blocking execution mode, BSP is freed to return to the calle= r and then
+  proceed to the next task without having to wait for APs. The follow= ing
+  sequence needs to occur in a non-blocking execution mode:
+
+    -# The caller that intends to use this MP Services Prot= ocol in non-blocking
+       mode creates WaitEvent by calling the= EFI CreateEvent() service.  The caller
+       invokes EFI_MP_SERVICES_PROTOCOL.Star= tupAllAPs(). If the parameter WaitEvent
+       is not NULL, then StartupAllAPs() exe= cutes in non-blocking mode. It requests
+       the function specified by Procedure t= o be started on all the enabled APs,
+       and releases the BSP to continue with= other tasks.
+    -# The caller can use the CheckEvent() and WaitForEvent= () services to check
+       the state of the WaitEvent created in= step 1.
+    -# When the APs complete their task or TimeoutInMicroSe= condss expires, the MP
+       Service signals WaitEvent by calling = the EFI SignalEvent() function. If
+       FailedCpuList is not NULL, its conten= t is available when WaitEvent is
+       signaled. If all APs returned from Pr= ocedure prior to the timeout, then
+       FailedCpuList is set to NULL. If not = all APs return from Procedure before
+       the timeout, then FailedCpuList is fi= lled in with the list of the failed
+       APs. The buffer is allocated by MP Se= rvice Protocol using AllocatePool().
+       It is the caller's responsibility to = free the buffer with FreePool() service.
+    -# This invocation of SignalEvent() function informs th= e caller that invoked
+       EFI_MP_SERVICES_PROTOCOL.StartupAllAP= s() that either all the APs completed
+       the specified task or a timeout occur= red. The contents of FailedCpuList
+       can be examined to determine which AP= s did not complete the specified task
+       prior to the timeout.
+
+  @param[in]  This       &nbs= p;            A poin= ter to the EFI_MP_SERVICES_PROTOCOL
+            &n= bsp;            = ;             i= nstance.
+  @param[in]  Procedure       = ;        A pointer to the function to be= run on
+            &n= bsp;            = ;             e= nabled APs of the system. See type
+            &n= bsp;            = ;             E= FI_AP_PROCEDURE.
+  @param[in]  SingleThread      &n= bsp;     If TRUE, then all the enabled APs execute
+            &n= bsp;            = ;             t= he function specified by Procedure one by
+            &n= bsp;            = ;             o= ne, in ascending order of processor handle
+            &n= bsp;            = ;             n= umber.  If FALSE, then all the enabled APs
+            &n= bsp;            = ;             e= xecute the function specified by Procedure
+            &n= bsp;            = ;             s= imultaneously.
+  @param[in]  WaitEvent       = ;        The event created by the caller= with CreateEvent()
+            &n= bsp;            = ;             s= ervice.  If it is NULL, then execute in
+            &n= bsp;            = ;             b= locking mode. BSP waits until all APs finish
+            &n= bsp;            = ;             o= r TimeoutInMicroseconds expires.  If it's
+            &n= bsp;            = ;             n= ot NULL, then execute in non-blocking mode.
+            &n= bsp;            = ;             B= SP requests the function specified by
+            &n= bsp;            = ;             P= rocedure to be started on all the enabled
+            &n= bsp;            = ;             A= Ps, and go on executing immediately. If
+            &n= bsp;            = ;             a= ll return from Procedure, or TimeoutInMicroseconds
+            &n= bsp;            = ;             e= xpires, this event is signaled. The BSP
+            &n= bsp;            = ;             c= an use the CheckEvent() or WaitForEvent()
+            &n= bsp;            = ;             s= ervices to check the state of event.  Type
+            &n= bsp;            = ;             E= FI_EVENT is defined in CreateEvent() in
+            &n= bsp;            = ;             t= he Unified Extensible Firmware Interface
+            &n= bsp;            = ;             S= pecification.
+  @param[in]  TimeoutInMicroseconds   Indicates the ti= me limit in microseconds for
+            &n= bsp;            = ;             A= Ps to return from Procedure, either for
+            &n= bsp;            = ;             b= locking or non-blocking mode. Zero means
+            &n= bsp;            = ;             i= nfinity.  If the timeout expires before
+            &n= bsp;            = ;             a= ll APs return from Procedure, then Procedure
+            &n= bsp;            = ;             o= n the failed APs is terminated. All enabled
+            &n= bsp;            = ;             A= Ps are available for next function assigned
+            &n= bsp;            = ;             b= y EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+            &n= bsp;            = ;             o= r EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+            &n= bsp;            = ;             I= f the timeout expires in blocking mode,
+            &n= bsp;            = ;             B= SP returns EFI_TIMEOUT.  If the timeout
+            &n= bsp;            = ;             e= xpires in non-blocking mode, WaitEvent
+            &n= bsp;            = ;             i= s signaled with SignalEvent().
+  @param[in]  ProcedureArgument     &nb= sp; The parameter passed into Procedure for
+            &n= bsp;            = ;             a= ll APs.
+  @param[out] FailedCpuList       =     If NULL, this parameter is ignored. Otherwise,
+            &n= bsp;            = ;             i= f all APs finish successfully, then its
+            &n= bsp;            = ;             c= ontent is set to NULL. If not all APs
+            &n= bsp;            = ;             f= inish before timeout expires, then its
+            &n= bsp;            = ;             c= ontent is set to address of the buffer
+            &n= bsp;            = ;             h= olding handle numbers of the failed APs.
+            &n= bsp;            = ;             T= he buffer is allocated by MP Service Protocol,
+            &n= bsp;            = ;             a= nd it's the caller's responsibility to
+            &n= bsp;            = ;             f= ree the buffer with FreePool() service.
+            &n= bsp;            = ;             I= n blocking mode, it is ready for consumption
+            &n= bsp;            = ;             w= hen the call returns. In non-blocking mode,
+            &n= bsp;            = ;             i= t is ready when WaitEvent is signaled.  The
+            &n= bsp;            = ;             l= ist of failed CPU is terminated by
+            &n= bsp;            = ;             E= ND_OF_CPU_LIST.
+
+  @retval EFI_SUCCESS        =      In blocking mode, all APs have finished before
+            &n= bsp;            = ;         the timeout expired.
+  @retval EFI_SUCCESS        =      In non-blocking mode, function has been dispatched=
+            &n= bsp;            = ;         to all enabled APs.
+  @retval EFI_UNSUPPORTED       &n= bsp; A non-blocking mode request was made after the
+            &n= bsp;            = ;         UEFI event EFI_EVENT_GROU= P_READY_TO_BOOT was
+            &n= bsp;            = ;         signaled.
+  @retval EFI_DEVICE_ERROR        = Caller processor is AP.
+  @retval EFI_NOT_STARTED       &n= bsp; No enabled APs exist in the system.
+  @retval EFI_NOT_READY       &nbs= p;   Any enabled APs are busy.
+  @retval EFI_TIMEOUT        =      In blocking mode, the timeout expired before
+            &n= bsp;            = ;         all enabled APs have fini= shed.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE       =    Procedure,
+  IN  BOOLEAN        &nb= sp;          SingleThread,
+  IN  EFI_EVENT        &= nbsp;        WaitEvent   =             OPTIONAL= ,
+  IN  UINTN         = ;            Timeout= InMicroseconds,
+  IN  VOID         =              *P= rocedureArgument      OPTIONAL,
+  OUT UINTN         &nbs= p;           **FailedCpuL= ist         OPTIONAL
+  )
+{
+  return MpInitLibStartupAllAPs (
+           Procedure, +           SingleThread,=
+           WaitEvent, +           TimeoutInMicr= oseconds,
+           ProcedureArgu= ment,
+           FailedCpuList=
+           );
+}
+
+/**
+  This service lets the caller get one enabled AP to execute a caller= -provided
+  function. The caller can request the BSP to either wait for the com= pletion
+  of the AP or just proceed with the next task by using the EFI event= mechanism.
+  See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on no= n-blocking
+  execution support.  This service may only be called from the B= SP.
+
+  This function is used to dispatch one enabled AP to the function sp= ecified by
+  Procedure passing in the argument specified by ProcedureArgument.&n= bsp; If WaitEvent
+  is NULL, execution is in blocking mode. The BSP waits until the AP = finishes or
+  TimeoutInMicroSecondss expires. Otherwise, execution is in non-bloc= king mode.
+  BSP proceeds to the next task without waiting for the AP. If a non-= blocking mode
+  is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is = signaled,
+  then EFI_UNSUPPORTED must be returned.
+
+  If the timeout specified by TimeoutInMicroseconds expires before th= e AP returns
+  from Procedure, then execution of Procedure by the AP is terminated= . The AP is
+  available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupA= llAPs() and
+  EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+  @param[in]  This       &nbs= p;            A poin= ter to the EFI_MP_SERVICES_PROTOCOL
+            &n= bsp;            = ;             i= nstance.
+  @param[in]  Procedure       = ;        A pointer to the function to be= run on the
+            &n= bsp;            = ;             d= esignated AP of the system. See type
+            &n= bsp;            = ;             E= FI_AP_PROCEDURE.
+  @param[in]  ProcessorNumber      = ;   The handle number of the AP. The range is
+            &n= bsp;            = ;             f= rom 0 to the total number of logical
+            &n= bsp;            = ;             p= rocessors minus 1. The total number of
+            &n= bsp;            = ;             l= ogical processors can be retrieved by
+            &n= bsp;            = ;             E= FI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+  @param[in]  WaitEvent       = ;        The event created by the caller= with CreateEvent()
+            &n= bsp;            = ;             s= ervice.  If it is NULL, then execute in
+            &n= bsp;            = ;             b= locking mode. BSP waits until this AP finish
+            &n= bsp;            = ;             o= r TimeoutInMicroSeconds expires.  If it's
+            &n= bsp;            = ;             n= ot NULL, then execute in non-blocking mode.
+            &n= bsp;            = ;             B= SP requests the function specified by
+            &n= bsp;            = ;             P= rocedure to be started on this AP,
+            &n= bsp;            = ;             a= nd go on executing immediately. If this AP
+            &n= bsp;            = ;             r= eturn from Procedure or TimeoutInMicroSeconds
+            &n= bsp;            = ;             e= xpires, this event is signaled. The BSP
+            &n= bsp;            = ;             c= an use the CheckEvent() or WaitForEvent()
+            &n= bsp;            = ;             s= ervices to check the state of event.  Type
+            &n= bsp;            = ;             E= FI_EVENT is defined in CreateEvent() in
+            &n= bsp;            = ;             t= he Unified Extensible Firmware Interface
+            &n= bsp;            = ;             S= pecification.
+  @param[in]  TimeoutInMicroseconds   Indicates the ti= me limit in microseconds for
+            &n= bsp;            = ;             t= his AP to finish this Procedure, either for
+            &n= bsp;            = ;             b= locking or non-blocking mode. Zero means
+            &n= bsp;            = ;             i= nfinity.  If the timeout expires before
+            &n= bsp;            = ;             t= his AP returns from Procedure, then Procedure
+            &n= bsp;            = ;             o= n the AP is terminated. The
+            &n= bsp;            = ;             A= P is available for next function assigned
+            &n= bsp;            = ;             b= y EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+            &n= bsp;            = ;             o= r EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+            &n= bsp;            = ;             I= f the timeout expires in blocking mode,
+            &n= bsp;            = ;             B= SP returns EFI_TIMEOUT.  If the timeout
+            &n= bsp;            = ;             e= xpires in non-blocking mode, WaitEvent
+            &n= bsp;            = ;             i= s signaled with SignalEvent().
+  @param[in]  ProcedureArgument     &nb= sp; The parameter passed into Procedure on the
+            &n= bsp;            = ;             s= pecified AP.
+  @param[out] Finished        = ;        If NULL, this parameter is igno= red.  In
+            &n= bsp;            = ;             b= locking mode, this parameter is ignored.
+            &n= bsp;            = ;             I= n non-blocking mode, if AP returns from
+            &n= bsp;            = ;             P= rocedure before the timeout expires, its
+            &n= bsp;            = ;             c= ontent is set to TRUE. Otherwise, the
+            &n= bsp;            = ;             v= alue is set to FALSE. The caller can
+            &n= bsp;            = ;             d= etermine if the AP returned from Procedure
+            &n= bsp;            = ;             b= y evaluating this value.
+
+  @retval EFI_SUCCESS        =      In blocking mode, specified AP finished before
+            &n= bsp;            = ;         the timeout expires.
+  @retval EFI_SUCCESS        =      In non-blocking mode, the function has been
+            &n= bsp;            = ;         dispatched to specified A= P.
+  @retval EFI_UNSUPPORTED       &n= bsp; A non-blocking mode request was made after the
+            &n= bsp;            = ;         UEFI event EFI_EVENT_GROU= P_READY_TO_BOOT was
+            &n= bsp;            = ;         signaled.
+  @retval EFI_DEVICE_ERROR        = The calling processor is an AP.
+  @retval EFI_TIMEOUT        =      In blocking mode, the timeout expired before
+            &n= bsp;            = ;         the specified AP has fini= shed.
+  @retval EFI_NOT_READY       &nbs= p;   The specified AP is busy.
+  @retval EFI_NOT_FOUND       &nbs= p;   The processor with the handle specified by
+            &n= bsp;            = ;         ProcessorNumber does not = exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies= the BSP or disabled AP.
+  @retval EFI_INVALID_PARAMETER   Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  EFI_AP_PROCEDURE       =    Procedure,
+  IN  UINTN         = ;            Process= orNumber,
+  IN  EFI_EVENT        &= nbsp;        WaitEvent   =             OPTIONAL= ,
+  IN  UINTN         = ;            Timeout= InMicroseconds,
+  IN  VOID         =              *P= rocedureArgument      OPTIONAL,
+  OUT BOOLEAN         &n= bsp;         *Finished  &= nbsp;            OPT= IONAL
+  )
+{
+  return MpInitLibStartupThisAP (
+           Procedure, +           ProcessorNumb= er,
+           WaitEvent, +           TimeoutInMicr= oseconds,
+           ProcedureArgu= ment,
+           Finished
+           );
+}
+
+/**
+  This service switches the requested AP to be the BSP from that poin= t onward.
+  This service changes the BSP for all purposes.   This cal= l can only be performed
+  by the current BSP.
+
+  This service switches the requested AP to be the BSP from that poin= t onward.
+  This service changes the BSP for all purposes. The new BSP can take= over the
+  execution of the old BSP and continue seamlessly from where the old= one left
+  off. This service may not be supported after the UEFI Event EFI_EVE= NT_GROUP_READY_TO_BOOT
+  is signaled.
+
+  If the BSP cannot be switched prior to the return from this service= , then
+  EFI_UNSUPPORTED must be returned.
+
+  @param[in] This        &nbs= p;     A pointer to the EFI_MP_SERVICES_PROTOCOL instan= ce.
+  @param[in] ProcessorNumber   The handle number of AP that= is to become the new
+            &n= bsp;            = ;      BSP. The range is from 0 to the total numbe= r of
+            &n= bsp;            = ;      logical processors minus 1. The total numbe= r of
+            &n= bsp;            = ;      logical processors can be retrieved by
+            &n= bsp;            = ;      EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors().
+  @param[in] EnableOldBSP      If TRUE, then= the old BSP will be listed as an
+            &n= bsp;            = ;      enabled AP. Otherwise, it will be disabled.=
+
+  @retval EFI_SUCCESS        =      BSP successfully switched.
+  @retval EFI_UNSUPPORTED       &n= bsp; Switching the BSP cannot be completed prior to
+            &n= bsp;            = ;         this service returning. +  @retval EFI_UNSUPPORTED       &n= bsp; Switching the BSP is not supported.
+  @retval EFI_DEVICE_ERROR        = The calling processor is an AP.
+  @retval EFI_NOT_FOUND       &nbs= p;   The processor with the handle specified by
+            &n= bsp;            = ;         ProcessorNumber does not = exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies= the current BSP or
+            &n= bsp;            = ;         a disabled AP.
+  @retval EFI_NOT_READY       &nbs= p;   The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN         = ;           ProcessorNumb= er,
+  IN  BOOLEAN        &nb= sp;         EnableOldBSP
+  )
+{
+  return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
+}
+
+/**
+  This service lets the caller enable or disable an AP from this poin= t onward.
+  This service may only be called from the BSP.
+
+  This service allows the caller enable or disable an AP from this po= int onward.
+  The caller can optionally specify the health status of the AP by He= alth. If
+  an AP is being disabled, then the state of the disabled AP is imple= mentation
+  dependent. If an AP is enabled, then the implementation must guaran= tee that a
+  complete initialization sequence is performed on the AP, so the AP = is in a state
+  that is compatible with an MP operating system. This service may no= t be supported
+  after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+  If the enable or disable AP operation cannot be completed prior to = the return
+  from this service, then EFI_UNSUPPORTED must be returned.
+
+  @param[in] This        &nbs= p;     A pointer to the EFI_MP_SERVICES_PROTOCOL instan= ce.
+  @param[in] ProcessorNumber   The handle number of AP.
+            &n= bsp;            = ;      The range is from 0 to the total number of<= br> +            &n= bsp;            = ;      logical processors minus 1. The total numbe= r of
+            &n= bsp;            = ;      logical processors can be retrieved by
+            &n= bsp;            = ;      EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors().
+  @param[in] EnableAP        =   Specifies the new state for the processor for
+            &n= bsp;            = ;      enabled, FALSE for disabled.
+  @param[in] HealthFlag        If = not NULL, a pointer to a value that specifies
+            &n= bsp;            = ;      the new health status of the AP. This flag<= br> +            &n= bsp;            = ;      corresponds to StatusFlag defined in
+            &n= bsp;            = ;      EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo()= . Only
+            &n= bsp;            = ;      the PROCESSOR_HEALTH_STATUS_BIT is used. Al= l other
+            &n= bsp;            = ;      bits are ignored.  If it is NULL, this= parameter
+            &n= bsp;            = ;      is ignored.
+
+  @retval EFI_SUCCESS        =      The specified AP was enabled or disabled successfu= lly.
+  @retval EFI_UNSUPPORTED       &n= bsp; Enabling or disabling an AP cannot be completed
+            &n= bsp;            = ;         prior to this service ret= urning.
+  @retval EFI_UNSUPPORTED       &n= bsp; Enabling or disabling an AP is not supported.
+  @retval EFI_DEVICE_ERROR        = The calling processor is an AP.
+  @retval EFI_NOT_FOUND       &nbs= p;   Processor with the handle specified by ProcessorNumber
+            &n= bsp;            = ;         does not exist.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber specifies= the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+  IN  EFI_MP_SERVICES_PROTOCOL  *This,
+  IN  UINTN         = ;            Process= orNumber,
+  IN  BOOLEAN        &nb= sp;          EnableAP,
+  IN  UINT32        &nbs= p;           *HealthFlag = OPTIONAL
+  )
+{
+  return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthF= lag);
+}
+
+/**
+  This return the handle number for the calling processor.  This= service may be
+  called from the BSP and APs.
+
+  This service returns the processor handle number for the calling pr= ocessor.
+  The returned value is in the range from 0 to the total number of lo= gical
+  processors minus 1. The total number of logical processors can be r= etrieved
+  with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service= may be
+  called from the BSP and APs. If ProcessorNumber is NULL, then EFI_I= NVALID_PARAMETER
+  is returned. Otherwise, the current processors handle number is ret= urned in
+  ProcessorNumber, and EFI_SUCCESS is returned.
+
+  @param[in]  This       &nbs= p;     A pointer to the EFI_MP_SERVICES_PROTOCOL instan= ce.
+  @param[out] ProcessorNumber  Pointer to the handle number of A= P.
+            &n= bsp;            = ;      The range is from 0 to the total number of<= br> +            &n= bsp;            = ;      logical processors minus 1. The total numbe= r of
+            &n= bsp;            = ;      logical processors can be retrieved by
+            &n= bsp;            = ;      EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcess= ors().
+
+  @retval EFI_SUCCESS        =      The current processor handle number was returned +            &n= bsp;            = ;         in ProcessorNumber.
+  @retval EFI_INVALID_PARAMETER   ProcessorNumber is NULL.<= br> +
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+  IN EFI_MP_SERVICES_PROTOCOL  *This,
+  OUT UINTN         &nbs= p;          *ProcessorNumber +  )
+{
+  return MpInitLibWhoAmI (ProcessorNumber);
+}
+
+/**
+  Initialize Multi-processor support.
+**/
+VOID
+InitializeMpSupport (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       NumberOfProcessors;
+  UINTN       NumberOfEnabledProcessors= ;
+
+  //
+  // Wakeup APs to do initialization
+  //
+  Status =3D MpInitLibInitialize ();
+  ASSERT_EFI_ERROR (Status);
+
+  MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &Numbe= rOfEnabledProcessors);
+  mNumberOfProcessors =3D NumberOfProcessors;
+  DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfPr= ocessors));
+
+  Status =3D gBS->InstallMultipleProtocolInterfaces (
+            &n= bsp;     &mMpServiceHandle,
+            &n= bsp;     &gEfiMpServiceProtocolGuid,
+            &n= bsp;     &mMpServicesTemplate,
+            &n= bsp;     NULL
+            &n= bsp;     );
+  ASSERT_EFI_ERROR (Status);
+}
diff --git a/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c b/UefiCpuPkg/CpuDxe/= LoongArch64/Exception.c
new file mode 100644
index 0000000000..96def89936
--- /dev/null
+++ b/UefiCpuPkg/CpuDxe/LoongArch64/Exception.c
@@ -0,0 +1,159 @@
+/** @file Exception.c
+
+  CPU DXE Module initialization exception instance.
+
+  Copyright (c) 2024, Loongson Technology Corporation Limited. All ri= ghts reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "CpuDxe.h"
+#include <Guid/VectorHandoffTable.h>
+#include <Library/CpuExceptionHandlerLib.h>
+#include <Register/LoongArch64/Csr.h>
+
+VOID
+ExceptionEntryStart (
+  VOID
+  );
+
+VOID
+ExceptionEntryEnd (
+  VOID
+  );
+
+/**
+  This function registers and enables the handler specified by Interr= uptHandler for a processor
+  interrupt or exception type specified by InterruptType. If Interrup= tHandler is NULL, then the
+  handler for the processor interrupt or exception type specified by = InterruptType is uninstalled.
+  The installed handler is called once for each processor interrupt o= r exception.
+
+  @param  InterruptType    A pointer to the proce= ssor's current interrupt state. Set to TRUE if interrupts
+            &n= bsp;            = ;  are enabled and FALSE if interrupts are disabled.
+  @param  InterruptHandler A pointer to a function of type EFI_C= PU_INTERRUPT_HANDLER that is called
+            &n= bsp;            = ;  when a processor interrupt occurs. If this parameter is NULL, then = the handler
+            &n= bsp;            = ;  will be uninstalled.
+
+  @retval EFI_SUCCESS        =    The handler for the processor interrupt was successfully insta= lled or uninstalled.
+  @retval EFI_ALREADY_STARTED   InterruptHandler is not NUL= L, and a handler for InterruptType was
+            &n= bsp;            = ;       previously installed.
+  @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handl= er for InterruptType was not
+            &n= bsp;            = ;       previously installed.
+  @retval EFI_UNSUPPORTED       The int= errupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+RegisterInterruptHandler (
+  IN EFI_EXCEPTION_TYPE       &nbs= p; InterruptType,
+  IN EFI_CPU_INTERRUPT_HANDLER  InterruptHandler
+  )
+{
+  return (EFI_STATUS)RegisterCpuInterruptHandler (InterruptType, Inte= rruptHandler);
+}
+
+/**
+  Update the exception start entry code.
+
+  @retval EFI_SUCCESS        =    Update the exception start entry code down.
+  @retval EFI_OUT_OF_RESOURCES  The start entry code size out of= bounds.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateExceptionStartEntry (
+  VOID
+  )
+{
+  EFI_PHYSICAL_ADDRESS  ExceptionStartEntry;
+  UINTN          &n= bsp;      VectorLength;
+  UINTN          &n= bsp;      MaxLength;
+  UINTN          &n= bsp;      MaxSizeOfVector;
+
+  VectorLength =3D (UINTN)ExceptionEntryEnd - (UINTN)ExceptionEntrySt= art;
+
+  //
+  // A vector is up to 512 bytes.
+  //
+  MaxSizeOfVector =3D 512;
+  MaxLength       =3D (MAX_LOONGARCH_EX= CEPTION + MAX_LOONGARCH_INTERRUPT) * MaxSizeOfVector;
+
+  if (VectorLength > MaxLength) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ExceptionStartEntry =3D PcdGet64 (PcdCpuExceptionVectorBaseAddress)= ;
+
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, Vecto= rLength);
+  CopyMem ((VOID *)ExceptionStartEntry, (VOID *)ExceptionEntryStart, = VectorLength);
+  InvalidateInstructionCacheRange ((VOID *)ExceptionStartEntry, Vecto= rLength);
+  InvalidateDataCache ();
+
+  //
+  // If PcdCpuExceptionVectorBaseAddress is not used during SEC and P= EI stages, the exception
+  // base addres is set to PcdCpuExceptionVectorBaseAddress.
+  //
+  if (CsrRead (LOONGARCH_CSR_EBASE) !=3D ExceptionStartEntry) {
+    SetExceptionBaseAddress (ExceptionStartEntry);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Initialize interrupt handling for DXE phase.
+
+  @param  Cpu A pointer of EFI_CPU_ARCH_PROTOCOL instance.
+
+  @return VOID.
+
+**/
+VOID
+InitializeExceptions (
+  IN EFI_CPU_ARCH_PROTOCOL  *Cpu
+  )
+{
+  EFI_STATUS         &nb= sp;     Status;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfoList;
+  EFI_VECTOR_HANDOFF_INFO  *VectorInfo;
+  BOOLEAN          =         IrqEnabled;
+
+  VectorInfo =3D (EFI_VECTOR_HANDOFF_INFO *)NULL;
+  Status     =3D EfiGetSystemConfigurationTable (= &gEfiVectorHandoffTableGuid, (VOID **)&VectorInfoList);
+
+  if ((Status =3D=3D EFI_SUCCESS) && (VectorInfoList !=3D NUL= L)) {
+    VectorInfo =3D VectorInfoList;
+  }
+
+  //
+  // Disable interrupts
+  //
+  Cpu->GetInterruptState (Cpu, &IrqEnabled);
+  if (IrqEnabled) {
+    Cpu->DisableInterrupt (Cpu);
+  }
+
+  //
+  // Update the Exception Start Entry code to point into CpuDxe.
+  //
+  Status =3D UpdateExceptionStartEntry ();
+  if (EFI_ERROR (Status)) {
+    DebugPrint (EFI_D_ERROR, "[%a]: Exception start en= try code out of bounds!\n", __func__);
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  //
+  // Intialize the CpuExceptionHandlerLib so we take over the excepti= on vector table from the DXE Core
+  //
+  Status =3D InitializeCpuExceptionHandlers (VectorInfo);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Enable interrupts
+  //
+  DebugPrint (EFI_D_INFO, "InitializeExceptions,IrqEnabled =3D %= x\n", IrqEnabled);
+  if (!IrqEnabled) {
+    Status =3D Cpu->EnableInterrupt (Cpu);
+  }
+
+  ASSERT_EFI_ERROR (Status);
+}
--
2.27.0

_._,_._,_

Groups.io Links:

=20 You receive all messages sent to this group. =20 =20

View/Reply Online (#117076) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [rebecca@openfw.io]

_._,_._,_
--_000_MN6PR11MB8244A7C219BB6BFAD27AEF318C362MN6PR11MB8244namp_--