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 DA34974003B for ; Tue, 19 Dec 2023 06:30:40 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=z+m178UaEC06tQMsONnX3jB9sO1yn7Mny9mWn4MRpZA=; c=relaxed/simple; d=groups.io; h=ARC-Seal:ARC-Message-Signature:ARC-Authentication-Results:From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type:Content-Transfer-Encoding; s=20140610; t=1702967439; v=1; b=bAqh61Drn60tvaVuYtVFXTNkDiYoWTPm7WBgDCgK43hw1ceyfsvVhV5Sttg7sL4MIVdRYuvB kGnU0eBi4nog7xxucZzm5NVPspQS0HB/84wGJ6aRUXPnCfEha4chI00YEe7sxHRG68cEGeVjzQN Lks70qb3orjm2rkHVKTa/5SQ= X-Received: by 127.0.0.2 with SMTP id q1NKYY7687511xrh3FZDsBDL; Mon, 18 Dec 2023 22:30:39 -0800 X-Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by mx.groups.io with SMTP id smtpd.web11.6879.1702967438652206280 for ; Mon, 18 Dec 2023 22:30:38 -0800 X-IronPort-AV: E=McAfee;i="6600,9927,10928"; a="8986391" X-IronPort-AV: E=Sophos;i="6.04,287,1695711600"; d="scan'208";a="8986391" X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Dec 2023 22:30:26 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10928"; a="899249237" X-IronPort-AV: E=Sophos;i="6.04,287,1695711600"; d="scan'208";a="899249237" X-Received: from orsmsx602.amr.corp.intel.com ([10.22.229.15]) by orsmga004.jf.intel.com with ESMTP/TLS/AES256-GCM-SHA384; 18 Dec 2023 22:30:25 -0800 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX602.amr.corp.intel.com (10.22.229.15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Mon, 18 Dec 2023 22:30:25 -0800 X-Received: from orsmsx612.amr.corp.intel.com (10.22.229.25) 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; Mon, 18 Dec 2023 22:30:24 -0800 X-Received: from orsedg603.ED.cps.intel.com (10.7.248.4) by orsmsx612.amr.corp.intel.com (10.22.229.25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend Transport; Mon, 18 Dec 2023 22:30:24 -0800 X-Received: from NAM12-MW2-obe.outbound.protection.outlook.com (104.47.66.41) by edgegateway.intel.com (134.134.137.100) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 18 Dec 2023 22:30:24 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=PyRmZUl2b512LnyU+eO6k+FsWB4XDtcljxxj6mSFG7yFD3Wj58NciwB03pwMoO+9w2hFQBnCuwIlXIzKFLCHJA9bPklP0ue917ctyuDSBQhcUhuJdh7BopI5YVb1Sih0HYSG5mdAP8z3kDIyaOXg6qT0ZdIBEecfoApSAuC3m9Qgm0kQOAttRB4CfTLyAw9R8ktRMhb+vrhJ9a0ryE9eK6lT5lcwoA2lBmkRXV+Xixfiit7BapVlmXmHC2xYR6N551XJs9SmGwS9j4ct6GghYFu5sThzxmFOnsPAJ3o/pIz/2V3BOSy5NrZ9cR+KIU6RuHBJcHwXituG81RlQLT3qQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=gLQCe9gq74Fp66wAe576QeiS34hhzXSWE76U8U5G/c4=; b=fbmDOfPs9eaZFByt3ttN0Ygs2xc5DnBNnlrpkeaKpJdtPK0zd5azMLDFo5PSZXhHY5hD8YeH9kyEFFHpvY0mH/TsHaxU4dBzSRM50xpncI3ak6geEFq+JO91L+n2i1Nh3u8ba4ds5VnJ4sWe31gGk7MVvsnLoSU5Bh7gHQp8FIjKHmBgLUobe3WTqIDbDJ87ovcDCOmi3ZEeYY4TS4xiZw2fe7IpP6FhdNBl19gNumI5LT8sv6v39+qM5wVIZln4FDo7rN8aKCdKpLjmlrlUvipM+Zw7Ul1XsWZEyka14Lom8CeE+d4sr4EoDGKosVJqFZuecUNNqSHdHSQlQ4eyRw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com (2603:10b6:208:470::14) by MN0PR11MB6232.namprd11.prod.outlook.com (2603:10b6:208:3c3::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7091.38; Tue, 19 Dec 2023 06:30:20 +0000 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::b614:1f5e:8b0c:9858]) by MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::b614:1f5e:8b0c:9858%4]) with mapi id 15.20.7091.034; Tue, 19 Dec 2023 06:30:20 +0000 From: "Ni, Ray" To: Chao Li , "devel@edk2.groups.io" CC: "Dong, Eric" , "Kumar, Rahul R" , Gerd Hoffmann Subject: Re: [edk2-devel] [PATCH v4 14/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Thread-Topic: [PATCH v4 14/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Thread-Index: AQHaLPz6N21BjYsNbEyAfokTbxMEXLCwL3Uw Date: Tue, 19 Dec 2023 06:30:20 +0000 Message-ID: References: <20231212130932.2467028-1-lichao@loongson.cn> <20231212131227.2470922-1-lichao@loongson.cn> In-Reply-To: <20231212131227.2470922-1-lichao@loongson.cn> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-publictraffictype: Email x-ms-traffictypediagnostic: MN6PR11MB8244:EE_|MN0PR11MB6232:EE_ x-ms-office365-filtering-correlation-id: 1db796d9-95d7-4fe9-709a-08dc005bf93b x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: jm5r9KDL7NpOGNr1WPGwYuGkG7qA9vKMvBkmHri9TNK+mDLBxR5C3ZPfnLq19WYZ/DW4T7GCjbX8YeUkMAH/xCucXe/VksA7IgHRr4ZBGUZgdKepOTS7HLaM/Jz9xAL4XfEmLnEyqYN+RzuUWTMFbcJ9l3VsxMM3n5kt9keswM8aR+gCDQTV7rKwlSNF+UqZG6Mj0+OALvQla98qdshIULUKLS/Et1Yyz4YIOYT3UGE0I6GoVQHjyq62Hbtsh2wI27PhU/4o6yPPG0hmshz6LPtBqmK7B7zG7gHQrr4w9rE0aiXBWnFDWJ/qtBb472EKigvfZlmYuTjizpDx/R3uJv3hO8TXiElz3aoBPKU+9dMDrAxRYy9BdaIUODoI2RiB0sYIpxEMf9yA6rSZOYm+II/cHVixn5h5RPBuQ+C3vSTdjgPD56u6FEaS+wi2BJp4mJ9jbd5j0Ly8FVmxgUP3+o/wB95WzVMf1jXlZU5mMa8Fkq+pui14uUq3THDwewoFUdjBhStX2q/B6OsRe/K0XjlkuzWm+Fz7yePQ+ZmYw+7SG1Hlm5ATAh/oNmPXSr38p2Sy42JC5PWHTpXx30KoVEs5GUtDzizKJu57x9mtKoI= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?HeeIx6BW+NVIkoQHCKflaIY2UMsxz+u+jJcM7/m+dn3ziXmGg9sqx6T178TH?= =?us-ascii?Q?evWz1QvYjZ1I6EW1AV1xGewLZk3MMYuFhnlON0MK0WoiQTZr8NMzd/sMfK97?= =?us-ascii?Q?e9pgwdxJOAC29AIZf2o4vR934f24FPOaHPQHNebXdeynfzGu+Dm887vOTc9o?= =?us-ascii?Q?9CjaRB0BkQHqoUXPBBSOS6fme6BQOMKFpoHdfgO0lbjR7OYJ9QRxeh951JxD?= =?us-ascii?Q?f9epDco1j3zgXo6tTKbgUx3gpRry64/FWVNQyZzmoYvACYMdxqWT0nXLP8tn?= =?us-ascii?Q?YHqvjlPWxebe76cPTTeJKV5/7mmumV/HAdmkRCPaxYLaNiHX1EIOLEg9Bz4D?= =?us-ascii?Q?q3/9FqLYn5CxDLoXxDCI/NKOCeo2MXO5QH2D2rmrM9jBVawtnBxNetpoJnqV?= =?us-ascii?Q?DUmzpKJbeyY2t2Q70EKXioUKa9s4I4gq3TAead7UoZfRY+LoxSp/S2kj31BM?= =?us-ascii?Q?h9XJlbWNKxx+LgYorNwieXC8ruMrU2Zc7+1KgXwrhT6/IgZmz4+mIIb5u0VH?= =?us-ascii?Q?z3SEQdSdKoADEU1w3jlsLrQPyKPAqviboW9BM022rdR3uqXCLSkp95mMPmK6?= =?us-ascii?Q?HkKw1mozV2GS7XcZlLvlGhfa8oH4VWNoQ56mNhudtZW3daQ4Jnl3tVbA3UCh?= =?us-ascii?Q?4QEGXidnkjmeXY5+turOvpKVoqvqubW6rC0j5/cr9rUzqLqZm6VWAxO+76wK?= =?us-ascii?Q?Xcg38a+FgoXxw9ReWTI9SSUxKmEdxhNVa0a336xruh5wtSH8WVguSsKCAhgm?= =?us-ascii?Q?Cm2b2+j5bNfa7QTSq+rMR/BlvlDsTymiINb9xzoKuNo04K68hWCvgzOUO0zP?= =?us-ascii?Q?dzxaiurRE+UcwfqT8wBFIjKhvlDI7mbiNsPXKexiEwW0rommt9N1sf1k3aNF?= =?us-ascii?Q?tWSR5MVeW1CD40pJ6CEgVp00jLh4BR0fassYDzqbMdg//ajrjWw3OMFyt5o3?= =?us-ascii?Q?ZaincCOqo1iUStXBZmmHotJNgrRjRzS5rWbDW0PjLedl5LFqbVrYXOORC3OK?= =?us-ascii?Q?hZjbtSql+Lme+E5M0PWmbakYYcHh25mY63J1u4jkIdT8NmXrbu4rwH6Y1TTa?= =?us-ascii?Q?tgufWagBBpr2I3xjPbwAYlMZ7VbYs5bPxZtQJ3w5PN7mkFEAyi0lY5uiOmpN?= =?us-ascii?Q?1XCeKDpV5B4SPBWghXRpyjDKq0yCqoOULSGml+WXOu3q8Y4rT2oFVYQFLX+2?= =?us-ascii?Q?GVtOLfa8Rt0HvTfroGMsAwxkW7IyGf/bLLFhfmgK578I3mS60elkoUfzKKiF?= =?us-ascii?Q?++0MNpzhbSo0gliYfht/QAlnNmsXE7PUXJzjlxeQAWaZS7g/qnQ7rs10k8ta?= =?us-ascii?Q?7A472MzCNDOEMC4WaWDIWDfYaXJxK/bAtJKAW1hhy57r8s5neDxAksL1HYOV?= =?us-ascii?Q?Jbnx5ziceC9w8EUOgxZVu+b2Mjc+FBMuiXBldth003KZwI5iOHHZfkjIuYnZ?= =?us-ascii?Q?5DwEF/VkiESlhrexQiSawjgmnm14Q3InVwEgaJ/zM1qAQsVTopd0KibVKEA/?= =?us-ascii?Q?mYyNuLy6MzOat1ENgWccSVF7Q7Swexv16z9TftnPpLuXq2Jo67OBgnIeY4Ye?= =?us-ascii?Q?MMcOmHEXXBXOZvUHZIs=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: 1db796d9-95d7-4fe9-709a-08dc005bf93b X-MS-Exchange-CrossTenant-originalarrivaltime: 19 Dec 2023 06:30:20.3039 (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: d8mhW3DzQxicQSeKhqnTFfeGHmUq8W/rCZqMVuIDvkZ0dM+tO7GkqAd3z9gunb9mUOmWDnkUZzXUihp4wv0vzQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR11MB6232 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 Reply-To: devel@edk2.groups.io,ray.ni@intel.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: 4bBerHw6DutQJwOrOrvY92Nrx7686176AA= Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=bAqh61Dr; 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; arc=reject ("signature check failed: fail, {[1] = sig:microsoft.com:reject}") Acked-by: Ray Ni Thanks, Ray > -----Original Message----- > From: Chao Li > Sent: Tuesday, December 12, 2023 9:12 PM > To: devel@edk2.groups.io > Cc: Dong, Eric ; Ni, Ray ; Kumar, > Rahul R ; Gerd Hoffmann > Subject: [PATCH v4 14/37] UefiCpuPkg: Add multiprocessor library for > LoongArch64 >=20 > Added a new library named LoongArch64MpInitLib. >=20 > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4584 >=20 > Cc: Eric Dong > Cc: Ray Ni > Cc: Rahul Kumar > Cc: Gerd Hoffmann > Signed-off-by: Chao Li > Acked-by: Ray Ni > --- > .../LoongArch64MpInitLib/DxeMpInitLib.inf | 45 + > .../LoongArch64MpInitLib/DxeMpInitLib.uni | 15 + > .../Library/LoongArch64MpInitLib/DxeMpLib.c | 480 +++++ > .../Library/LoongArch64MpInitLib/MpLib.c | 1596 > +++++++++++++++++ > .../Library/LoongArch64MpInitLib/MpLib.h | 361 ++++ > .../LoongArch64MpInitLib/PeiMpInitLib.inf | 37 + > .../LoongArch64MpInitLib/PeiMpInitLib.uni | 15 + > .../Library/LoongArch64MpInitLib/PeiMpLib.c | 404 +++++ > UefiCpuPkg/UefiCpuPkg.dsc | 2 + > 9 files changed, 2955 insertions(+) > create mode 100644 > UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf > create mode 100644 > UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni > create mode 100644 > UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c > create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c > create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h > create mode 100644 > UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > create mode 100644 > UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni > create mode 100644 UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c >=20 > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf > b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf > new file mode 100644 > index 0000000000..64f0508046 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf > @@ -0,0 +1,45 @@ > +## @file > +# LoongArch64 MP initialize support functions for DXE phase. > +# > +# Copyright (c) 2023, Loongson Technology Corporation Limited. All righ= ts > reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > + > +[Defines] > + INF_VERSION =3D 1.29 > + BASE_NAME =3D DxeMpInitLib > + MODULE_UNI_FILE =3D DxeMpInitLib.uni > + FILE_GUID =3D > C3B9ACAA-B67C-D3E0-E70D-7982B6EA2931 > + MODULE_TYPE =3D DXE_DRIVER > + VERSION_STRING =3D 1.1 > + LIBRARY_CLASS =3D MpInitLib|DXE_DRIVER > + > +[Sources.common] > + DxeMpLib.c > + MpLib.c > + MpLib.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[LibraryClasses] > + BaseLib > + CpuLib > + DebugAgentLib > + HobLib > + MemoryAllocationLib > + SynchronizationLib > + TimerLib > + UefiLib > + > +[Protocols] > + gEfiTimerArchProtocolGuid ## > SOMETIMES_CONSUMES > + > +[Pcd] > + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber > ## CONSUMES > + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds > ## CONSUMES > + > gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds > ## CONSUMES > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni > b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni > new file mode 100644 > index 0000000000..aebbdbbb0e > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.uni > @@ -0,0 +1,15 @@ > +// /** @file > +// MP Initialize Library instance for DXE driver. > +// > +// MP Initialize Library instance for DXE driver. > +// > +// Copyright (c) 2023, Loongson Technology Corporation Limited. All righ= ts > reserved.
> +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "MP > Initialize Library instance for DXE driver." > + > +#string STR_MODULE_DESCRIPTION #language en-US "MP > Initialize Library instance for DXE driver." > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c > b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c > new file mode 100644 > index 0000000000..26ca4c34fe > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c > @@ -0,0 +1,480 @@ > +/** @file > + LoongArch64 MP initialize support functions for DXE phase. > + > + Copyright (c) 2023, Loongson Technology Corporation Limited. All right= s > reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "MpLib.h" > + > +#include > +#include > +#include > + > +#include > + > +CPU_MP_DATA *mCpuMpData =3D NULL; > +EFI_EVENT mCheckAllApsEvent =3D NULL; > +volatile BOOLEAN mStopCheckAllApsStatus =3D TRUE; > + > +/** > + Enable Debug Agent to support source debugging on AP function. > + > +**/ > +VOID > +EnableDebugAgent ( > + VOID > + ) > +{ > + // > + // Initialize Debug Agent to support source level debug in DXE phase > + // > + InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL); > +} > + > +/** > + Get the pointer to CPU MP Data structure. > + > + @return The pointer to CPU MP Data structure. > +**/ > +CPU_MP_DATA * > +GetCpuMpData ( > + VOID > + ) > +{ > + ASSERT (mCpuMpData !=3D NULL); > + return mCpuMpData; > +} > + > +/** > + Save the pointer to CPU MP Data structure. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure will be > saved. > +**/ > +VOID > +SaveCpuMpData ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + mCpuMpData =3D CpuMpData; > +} > + > +/** > + Get available EfiBootServicesCode memory below 4GB by specified size. > + > + This buffer is required to safely transfer AP from real address mode t= o > + protected mode or long mode, due to the fact that the buffer returned = by > + GetWakeupBuffer() may be marked as non-executable. > + > + @param[in] BufferSize Wakeup transition buffer size. > + > + @retval other Return wakeup transition buffer address below 4GB. > + @retval 0 Cannot find free memory below 4GB. > +**/ > +UINTN > +GetModeTransitionBuffer ( > + IN UINTN BufferSize > + ) > +{ > + return 0; > +} > + > +/** > + Checks APs status and updates APs status if needed. > + > +**/ > +VOID > +CheckAndUpdateApsStatus ( > + VOID > + ) > +{ > + UINTN ProcessorNumber; > + EFI_STATUS Status; > + CPU_MP_DATA *CpuMpData; > + > + CpuMpData =3D GetCpuMpData (); > + > + // > + // First, check whether pending StartupAllAPs() exists. > + // > + if (CpuMpData->WaitEvent !=3D NULL) { > + Status =3D CheckAllAPs (); > + // > + // If all APs finish for StartupAllAPs(), signal the WaitEvent for i= t. > + // > + if (Status !=3D EFI_NOT_READY) { > + Status =3D gBS->SignalEvent > (CpuMpData->WaitEvent); > + CpuMpData->WaitEvent =3D NULL; > + } > + } > + > + // > + // Second, check whether pending StartupThisAPs() callings exist. > + // > + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; > ProcessorNumber++) { > + if (CpuMpData->CpuData[ProcessorNumber].WaitEvent =3D=3D NULL) { > + continue; > + } > + > + Status =3D CheckThisAP (ProcessorNumber); > + > + if (Status !=3D EFI_NOT_READY) { > + gBS->SignalEvent > (CpuMpData->CpuData[ProcessorNumber].WaitEvent); > + CpuMpData->CpuData[ProcessorNumber].WaitEvent =3D NULL; > + } > + } > +} > + > +/** > + Checks APs' status periodically. > + > + This function is triggered by timer periodically to check the > + state of APs for StartupAllAPs() and StartupThisAP() executed > + in non-blocking mode. > + > + @param[in] Event Event triggered. > + @param[in] Context Parameter passed with the event. > + > +**/ > +VOID > +EFIAPI > +CheckApsStatus ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + // > + // If CheckApsStatus() is not stopped, otherwise return immediately. > + // > + if (!mStopCheckAllApsStatus) { > + CheckAndUpdateApsStatus (); > + } > +} > + > +/** > + Initialize global data for MP support. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure. > +**/ > +VOID > +InitMpGlobalData ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + EFI_STATUS Status; > + > + SaveCpuMpData (CpuMpData); > + > + Status =3D gBS->CreateEvent ( > + EVT_TIMER | EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + CheckApsStatus, > + NULL, > + &mCheckAllApsEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Set timer to check all APs status. > + // > + Status =3D gBS->SetTimer ( > + mCheckAllApsEvent, > + TimerPeriodic, > + EFI_TIMER_PERIOD_MICROSECONDS ( > + PcdGet32 > (PcdCpuApStatusCheckIntervalInMicroSeconds) > + ) > + ); > + ASSERT_EFI_ERROR (Status); > +} > + > +/** > + This service executes a caller provided function on all enabled APs. > + > + @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 execute > + the function specified by > Procedure one by > + one, in ascending order of > processor handle > + number. If FALSE, then all > the enabled APs > + execute the function > specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. If it is NULL, then > execute in > + blocking mode. BSP waits > until all APs finish > + or TimeoutInMicroSeconds > expires. If it's > + not NULL, then execute in > non-blocking mode. > + BSP requests the function > specified by > + Procedure to be started on > all the enabled > + APs, and go on executing > immediately. If > + all return from Procedure, or > TimeoutInMicroSeconds > + expires, this event is signaled. > The BSP > + can use the CheckEvent() or > WaitForEvent() > + services to check the state of > event. Type > + EFI_EVENT is defined in > CreateEvent() in > + the Unified Extensible > Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. Zero means > + infinity. If the timeout > expires before > + all APs return from > Procedure, then Procedure > + on the failed APs is > terminated. All enabled > + APs are available for next > function assigned > + by MpInitLibStartupAllAPs() > or > + MPInitLibStartupThisAP(). > + If the timeout expires in > blocking mode, > + BSP returns EFI_TIMEOUT. > If the timeout > + expires in non-blocking mode, > WaitEvent > + 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 APs > + finish before timeout expires, > then its > + content is set to address of > the buffer > + holding handle numbers of > the failed APs. > + The buffer is allocated by MP > Initialization > + library, and it's the caller's > responsibility to > + free the buffer with > FreePool() service. > + In blocking mode, it is ready > for consumption > + when the call returns. In > non-blocking mode, > + it is ready when WaitEvent is > signaled. 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 after the > + UEFI event > EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_UNSUPPORTED WaitEvent is not NULL if > non-blocking mode is not > + supported. > + @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_NOT_READY MP Initialize Library is not > initialized. > + @retval EFI_TIMEOUT In blocking mode, the timeout > expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupAllAPs ( > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Temporarily stop checkAllApsStatus for avoid resource dead-lock. > + // > + mStopCheckAllApsStatus =3D TRUE; > + > + Status =3D StartupAllCPUsWorker ( > + Procedure, > + SingleThread, > + TRUE, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + FailedCpuList > + ); > + > + // > + // Start checkAllApsStatus > + // > + mStopCheckAllApsStatus =3D FALSE; > + > + return Status; > +} > + > +/** > + This service lets the caller get one enabled AP to execute a caller-pr= ovided > + function. > + > + @param[in] Procedure A pointer to the function to be > run on the > + designated AP of the system. > See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. > The range is > + from 0 to the total number of > logical > + processors minus 1. The > total number of > + logical processors can be > retrieved by > + > MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. If it is NULL, then > execute in > + blocking mode. BSP waits > until this AP finish > + or TimeoutInMicroSeconds > expires. If it's > + not NULL, then execute in > non-blocking 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 > TimeoutInMicroSeconds > + expires, this event is signaled. > The BSP > + can use the CheckEvent() or > WaitForEvent() > + services to check the state of > event. Type > + EFI_EVENT is defined in > CreateEvent() in > + the Unified Extensible > Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + this AP to finish this > Procedure, either for > + blocking or non-blocking > mode. Zero means > + infinity. If the timeout > expires before > + this AP returns from > Procedure, then Procedure > + on the AP is terminated. The > + AP is available for next > function assigned > + by MpInitLibStartupAllAPs() > or > + MpInitLibStartupThisAP(). > + If the timeout expires in > blocking mode, > + BSP returns EFI_TIMEOUT. > If the timeout > + expires in non-blocking mode, > WaitEvent > + 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 ignored. > + In non-blocking mode, if AP > returns from > + Procedure before the > timeout expires, its > + content is set to TRUE. > Otherwise, the > + value is set to FALSE. The > caller can > + determine if the AP returned > from Procedure > + 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 been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was > made after the > + UEFI event > EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_UNSUPPORTED WaitEvent is not NULL if > non-blocking mode is not > + supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_TIMEOUT In blocking mode, the timeout > expired before > + the specified AP has finished. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + @retval EFI_NOT_FOUND The processor with the handle > specified by > + 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 > +MpInitLibStartupThisAP ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + > + // > + // temporarily stop checkAllApsStatus for avoid resource dead-lock. > + // > + mStopCheckAllApsStatus =3D TRUE; > + > + Status =3D StartupThisAPWorker ( > + Procedure, > + ProcessorNumber, > + WaitEvent, > + TimeoutInMicroseconds, > + ProcedureArgument, > + Finished > + ); > + > + mStopCheckAllApsStatus =3D FALSE; > + > + return Status; > +} > + > +/** > + This service switches the requested AP to be the BSP from that point > onward. > + This service changes the BSP for all purposes. This call can only be > performed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to > become the new > + BSP. The range is from 0 to the total > number of > + logical processors minus 1. The total > number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @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 prior 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 BSP or > + a disabled AP. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibSwitchBSP ( > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableOldBSP > + ) > +{ > + return EFI_UNSUPPORTED; > +} > + > +/** > + This service lets the caller enable or disable an AP from this point o= nward. > + This service may only be called from the BSP. > + > + @param[in] ProcessorNumber The handle number of AP. > + The range is from 0 to the total > number of > + logical processors minus 1. The total > number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the > processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that > specifies > + 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. All other > + bits are ignored. If it is NULL, this > parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or > disabled successfully. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot > be completed > + prior to this service returning. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not > supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle > specified by ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the > BSP. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibEnableDisableAP ( > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ) > +{ > + return EFI_UNSUPPORTED; > +} > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c > b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c > new file mode 100644 > index 0000000000..5852a5c0c7 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c > @@ -0,0 +1,1596 @@ > +/** @file > + LoongArch64 CPU MP Initialize Library common functions. > + > + Copyright (c) 2023, Loongson Technology Corporation Limited. All right= s > reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "MpLib.h" > + > +#include > +#include > + > +EFI_GUID mCpuInitMpLibHobGuid =3D > CPU_INIT_MP_LIB_HOB_GUID; > +EFI_GUID mProcessorResourceHobGuid =3D > PROCESSOR_RESOURCE_HOB_GUID; > + > +/** > + Get the Application Processors state. > + > + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP > + > + @return The AP status > +**/ > +CPU_STATE > +GetApState ( > + IN CPU_AP_DATA *CpuData > + ) > +{ > + return CpuData->State; > +} > + > +/** > + Set the Application Processors state. > + > + @param[in] CpuData The pointer to CPU_AP_DATA of specified AP > + @param[in] State The AP status > +**/ > +VOID > +SetApState ( > + IN CPU_AP_DATA *CpuData, > + IN CPU_STATE State > + ) > +{ > + AcquireSpinLock (&CpuData->ApLock); > + CpuData->State =3D State; > + ReleaseSpinLock (&CpuData->ApLock); > +} > + > +/** > + Get APIC ID of the executing processor. > + > + @return 32-bit APIC ID of the executing processor. > +**/ > +UINT32 > +GetApicId ( > + VOID > + ) > +{ > + UINTN CpuNum; > + > + CpuNum =3D CsrRead (LOONGARCH_CSR_CPUNUM); > + > + return CpuNum & 0x3ff; > +} > + > +/** > + Find the current Processor number by APIC ID. > + > + @param[in] CpuMpData Pointer to PEI CPU MP Data > + @param[out] ProcessorNumber Return the pocessor number found > + > + @retval EFI_SUCCESS ProcessorNumber is found and > returned. > + @retval EFI_NOT_FOUND ProcessorNumber is not found. > +**/ > +EFI_STATUS > +GetProcessorNumber ( > + IN CPU_MP_DATA *CpuMpData, > + OUT UINTN *ProcessorNumber > + ) > +{ > + UINTN TotalProcessorNumber; > + UINTN Index; > + CPU_INFO_IN_HOB *CpuInfoInHob; > + > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)CpuMpData->CpuInfoInHob; > + > + TotalProcessorNumber =3D CpuMpData->CpuCount; > + for (Index =3D 0; Index < TotalProcessorNumber; Index++) { > + if (CpuInfoInHob[Index].ApicId =3D=3D GetApicId ()) { > + *ProcessorNumber =3D Index; > + return EFI_SUCCESS; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** > + Sort the APIC ID of all processors. > + > + This function sorts the APIC ID of all processors so that processor nu= mber > is > + assigned in the ascending order of APIC ID which eases MP debugging. > + > + @param[in] CpuMpData Pointer to PEI CPU MP Data > +**/ > +VOID > +SortApicId ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + UINTN Index1; > + UINTN Index2; > + UINTN Index3; > + UINT32 ApicId; > + CPU_INFO_IN_HOB CpuInfo; > + UINT32 ApCount; > + CPU_INFO_IN_HOB *CpuInfoInHob; > + volatile UINT32 *StartupApSignal; > + > + ApCount =3D CpuMpData->CpuCount - 1; > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)CpuMpData->CpuInfoInHob; > + if (ApCount !=3D 0) { > + for (Index1 =3D 0; Index1 < ApCount; Index1++) { > + Index3 =3D Index1; > + // > + // Sort key is the hardware default APIC ID > + // > + ApicId =3D CpuInfoInHob[Index1].ApicId; > + for (Index2 =3D Index1 + 1; Index2 <=3D ApCount; Index2++) { > + if (ApicId > CpuInfoInHob[Index2].ApicId) { > + Index3 =3D Index2; > + ApicId =3D CpuInfoInHob[Index2].ApicId; > + } > + } > + > + if (Index3 !=3D Index1) { > + CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof > (CPU_INFO_IN_HOB)); > + CopyMem ( > + &CpuInfoInHob[Index3], > + &CpuInfoInHob[Index1], > + sizeof (CPU_INFO_IN_HOB) > + ); > + CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof > (CPU_INFO_IN_HOB)); > + > + // > + // Also exchange the StartupApSignal. > + // > + StartupApSignal =3D > CpuMpData->CpuData[Index3].StartupApSignal; > + CpuMpData->CpuData[Index3].StartupApSignal =3D > + CpuMpData->CpuData[Index1].StartupApSignal; > + CpuMpData->CpuData[Index1].StartupApSignal =3D StartupApSignal; > + } > + } > + > + // > + // Get the processor number for the BSP > + // > + ApicId =3D GetApicId (); > + for (Index1 =3D 0; Index1 < CpuMpData->CpuCount; Index1++) { > + if (CpuInfoInHob[Index1].ApicId =3D=3D ApicId) { > + CpuMpData->BspNumber =3D (UINT32)Index1; > + break; > + } > + } > + } > +} > + > +/** > + Get pointer to Processor Resource Data structure from GUIDd HOB. > + > + @return The pointer to Processor Resource Data structure. > +**/ > +PROCESSOR_RESOURCE_DATA * > +GetProcessorResourceDataFromGuidedHob ( > + VOID > + ) > +{ > + EFI_HOB_GUID_TYPE *GuidHob; > + VOID *DataInHob; > + PROCESSOR_RESOURCE_DATA *ResourceData; > + > + ResourceData =3D NULL; > + GuidHob =3D GetFirstGuidHob (&mProcessorResourceHobGuid); > + if (GuidHob !=3D NULL) { > + DataInHob =3D GET_GUID_HOB_DATA (GuidHob); > + ResourceData =3D (PROCESSOR_RESOURCE_DATA *)(*(UINTN > *)DataInHob); > + } > + > + return ResourceData; > +} > + > +/** > + This function will get CPU count in the system. > + > + @param[in] CpuMpData Pointer to PEI CPU MP Data > + > + @return CPU count detected > +**/ > +UINTN > +CollectProcessorCount ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + PROCESSOR_RESOURCE_DATA *ProcessorResourceData; > + > + ProcessorResourceData =3D NULL; > + > + // > + // Set the default loop mode for APs. > + // > + CpuMpData->ApLoopMode =3D ApInRunLoop; > + > + // > + // Beacuse LoongArch does not have SIPI now, the APIC ID must be > obtained before > + // calling IPI to wake up the APs. If NULL is obtained, NODE0 Core0 > Mailbox0 is used > + // as the first broadcast method to wake up all APs, and all of APs wi= ll > read NODE0 > + // Core0 Mailbox0 in an infinit loop. > + // > + ProcessorResourceData =3D GetProcessorResourceDataFromGuidedHob (); > + > + if (ProcessorResourceData !=3D NULL) { > + CpuMpData->ApLoopMode =3D ApInHltLoop; > + CpuMpData->CpuCount =3D ProcessorResourceData->CpuCount; > + CpuMpData->CpuInfoInHob =3D > (UINTN)(ProcessorResourceData->CpuInfoInHob); > + } > + > + // > + // Send 1st broadcast IPI to APs to wakeup APs > + // > + CpuMpData->InitFlag =3D ApInitConfig; > + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, FALSE); > + CpuMpData->InitFlag =3D ApInitDone; > + > + // > + // When InitFlag =3D=3D ApInitConfig, WakeUpAP () guarantees all APs a= re > checked in. > + // FinishedCount is the number of check-in APs. > + // > + CpuMpData->CpuCount =3D CpuMpData->FinishedCount + 1; > + ASSERT (CpuMpData->CpuCount <=3D PcdGet32 > (PcdCpuMaxLogicalProcessorNumber)); > + > + // > + // Wait for all APs finished the initialization > + // > + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { > + CpuPause (); > + } > + > + // > + // Sort BSP/Aps by CPU APIC ID in ascending order > + // > + SortApicId (CpuMpData); > + > + DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", > CpuMpData->CpuCount)); > + > + return CpuMpData->CpuCount; > +} > + > +/** > + Initialize CPU AP Data when AP is wakeup at the first time. > + > + @param[in, out] CpuMpData Pointer to PEI CPU MP Data > + @param[in] ProcessorNumber The handle number of processor > + @param[in] BistData Processor BIST data > + > +**/ > +VOID > +InitializeApData ( > + IN OUT CPU_MP_DATA *CpuMpData, > + IN UINTN ProcessorNumber, > + IN UINT32 BistData > + ) > +{ > + CPU_INFO_IN_HOB *CpuInfoInHob; > + > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)(CpuMpData->CpuInfoInHob); > + > + CpuInfoInHob[ProcessorNumber].ApicId =3D GetApicId (); > + CpuInfoInHob[ProcessorNumber].Health =3D BistData; > + > + CpuMpData->CpuData[ProcessorNumber].Waiting =3D FALSE; > + CpuMpData->CpuData[ProcessorNumber].CpuHealthy =3D (BistData =3D=3D 0)= ? > TRUE : FALSE; > + > + InitializeSpinLock (&CpuMpData->CpuData[ProcessorNumber].ApLock); > + SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle); > +} > + > +/** > + Ap wake up function. > + > + Ap will wait for scheduling here, and if the IPI or wake-up signal is > enabled, > + Ap will preform the corresponding functions. > + > + @param[in] ApIndex Number of current executing AP > + @param[in] ExchangeInfo Pointer to the MP exchange info buffer > +**/ > +VOID > +EFIAPI > +ApWakeupFunction ( > + IN UINTN ApIndex, > + IN MP_CPU_EXCHANGE_INFO *ExchangeInfo > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + UINTN ProcessorNumber; > + volatile UINT32 *ApStartupSignalBuffer; > + EFI_AP_PROCEDURE Procedure; > + VOID *Parameter; > + > + CpuMpData =3D ExchangeInfo->CpuMpData; > + > + while (TRUE) { > + if (CpuMpData->InitFlag =3D=3D ApInitConfig) { > + ProcessorNumber =3D ApIndex; > + // > + // If the AP can running to here, then the BIST must be zero. > + // > + InitializeApData (CpuMpData, ProcessorNumber, 0); > + ApStartupSignalBuffer =3D > CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + } else { > + // > + // Execute AP function if AP is ready > + // > + GetProcessorNumber (CpuMpData, &ProcessorNumber); > + > + // > + // Clear AP start-up signal when AP waken up > + // > + ApStartupSignalBuffer =3D > CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + InterlockedCompareExchange32 ( > + (UINT32 *)ApStartupSignalBuffer, > + WAKEUP_AP_SIGNAL, > + 0 > + ); > + > + // > + // Invoke AP function here > + // > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D > CpuStateReady) { > + Procedure =3D > (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction; > + Parameter =3D (VOID > *)CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument; > + if (Procedure !=3D NULL) { > + SetApState (&CpuMpData->CpuData[ProcessorNumber], > CpuStateBusy); > + Procedure (Parameter); > + } > + > + SetApState (&CpuMpData->CpuData[ProcessorNumber], > CpuStateFinished); > + } > + } > + > + // > + // Updates the finished count > + // > + InterlockedIncrement ((UINT32 *)&CpuMpData->FinishedCount); > + > + while (TRUE) { > + // > + // Clean per-core mail box registers. > + // > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF1, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF2, 0x0); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, 0x0); > + > + // > + // Enable IPI interrupt and global interrupt > + // > + EnableLocalInterrupts (1 << 12); > + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFULL); > + EnableInterrupts (); > + > + // > + // Ap entry HLT mode > + // > + CpuSleep (); > + > + // > + // Disable global interrupts when wake up > + // > + DisableInterrupts (); > + > + // > + // Update CpuMpData > + // > + if (CpuMpData !=3D ExchangeInfo->CpuMpData) { > + CpuMpData =3D ExchangeInfo->CpuMpData; > + GetProcessorNumber (CpuMpData, &ProcessorNumber); > + ApStartupSignalBuffer =3D > CpuMpData->CpuData[ProcessorNumber].StartupApSignal; > + } > + > + // > + // Break out of the loop if wake up signal is not NULL. > + // > + if (*ApStartupSignalBuffer =3D=3D WAKEUP_AP_SIGNAL) { > + break; > + } > + } > + } > +} > + > +/** > + Calculate timeout value and return the current performance counter > value. > + > + Calculate the number of performance counter ticks required for a timeo= ut. > + If TimeoutInMicroseconds is 0, return value is also 0, which is recogn= ized > + as infinity. > + > + @param[in] TimeoutInMicroseconds Timeout value in microseconds. > + @param[out] CurrentTime Returns the current value of > the performance counter. > + > + @return Expected time stamp counter for timeout. > + If TimeoutInMicroseconds is 0, return value is also 0, which i= s > recognized > + as infinity. > + > +**/ > +UINT64 > +CalculateTimeout ( > + IN UINTN TimeoutInMicroseconds, > + OUT UINT64 *CurrentTime > + ) > +{ > + UINT64 TimeoutInSeconds; > + UINT64 TimestampCounterFreq; > + > + // > + // Read the current value of the performance counter > + // > + *CurrentTime =3D GetPerformanceCounter (); > + > + // > + // If TimeoutInMicroseconds is 0, return value is also 0, which is > recognized > + // as infinity. > + // > + if (TimeoutInMicroseconds =3D=3D 0) { > + return 0; > + } > + > + // > + // GetPerformanceCounterProperties () returns the timestamp counter's > frequency > + // in Hz. > + // > + TimestampCounterFreq =3D GetPerformanceCounterProperties (NULL, > NULL); > + > + // > + // Check the potential overflow before calculate the number of ticks f= or > the timeout value. > + // > + if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < > TimestampCounterFreq) { > + // > + // Convert microseconds into seconds if direct multiplication overfl= ows > + // > + TimeoutInSeconds =3D DivU64x32 (TimeoutInMicroseconds, 1000000); > + // > + // Assertion if the final tick count exceeds MAX_UINT64 > + // > + ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, > NULL) >=3D TimestampCounterFreq); > + return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds); > + } else { > + // > + // No overflow case, multiply the return value with > TimeoutInMicroseconds and then divide > + // it by 1,000,000, to get the number of ticks for the timeout value= . > + // > + return DivU64x32 ( > + MultU64x64 ( > + TimestampCounterFreq, > + TimeoutInMicroseconds > + ), > + 1000000 > + ); > + } > +} > + > +/** > + Checks whether timeout expires. > + > + Check whether the number of elapsed performance counter ticks required > for > + a timeout condition has been reached. > + If Timeout is zero, which means infinity, return value is always FALSE= . > + > + @param[in, out] PreviousTime On input, the value of the > performance counter > + when it was last read. > + On output, the current value of > the performance > + counter > + @param[in] TotalTime The total amount of elapsed time in > performance > + counter ticks. > + @param[in] Timeout The number of performance > counter ticks required > + to reach a timeout condition. > + > + @retval TRUE A timeout condition has been > reached. > + @retval FALSE A timeout condition has not been > reached. > + > +**/ > +BOOLEAN > +CheckTimeout ( > + IN OUT UINT64 *PreviousTime, > + IN UINT64 *TotalTime, > + IN UINT64 Timeout > + ) > +{ > + UINT64 Start; > + UINT64 End; > + UINT64 CurrentTime; > + INT64 Delta; > + INT64 Cycle; > + > + if (Timeout =3D=3D 0) { > + return FALSE; > + } > + > + GetPerformanceCounterProperties (&Start, &End); > + Cycle =3D End - Start; > + if (Cycle < 0) { > + Cycle =3D -Cycle; > + } > + > + Cycle++; > + CurrentTime =3D GetPerformanceCounter (); > + Delta =3D (INT64)(CurrentTime - *PreviousTime); > + if (Start > End) { > + Delta =3D -Delta; > + } > + > + if (Delta < 0) { > + Delta +=3D Cycle; > + } > + > + *TotalTime +=3D Delta; > + *PreviousTime =3D CurrentTime; > + if (*TotalTime > Timeout) { > + return TRUE; > + } > + > + return FALSE; > +} > + > +/** > + Helper function that waits until the finished AP count reaches the > specified > + limit, or the specified timeout elapses (whichever comes first). > + > + @param[in] CpuMpData Pointer to CPU MP Data. > + @param[in] FinishedApLimit The number of finished APs to wait for. > + @param[in] TimeLimit The number of microseconds to wait for. > +**/ > +VOID > +TimedWaitForApFinish ( > + IN CPU_MP_DATA *CpuMpData, > + IN UINT32 FinishedApLimit, > + IN UINT32 TimeLimit > + ) > +{ > + // > + // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0 > + // "infinity", so check for (TimeLimit =3D=3D 0) explicitly. > + // > + if (TimeLimit =3D=3D 0) { > + return; > + } > + > + CpuMpData->TotalTime =3D 0; > + CpuMpData->ExpectedTime =3D CalculateTimeout ( > + TimeLimit, > + &CpuMpData->CurrentTime > + ); > + while (CpuMpData->FinishedCount < FinishedApLimit && > + !CheckTimeout ( > + &CpuMpData->CurrentTime, > + &CpuMpData->TotalTime, > + CpuMpData->ExpectedTime > + )) > + { > + CpuPause (); > + } > + > + if (CpuMpData->FinishedCount >=3D FinishedApLimit) { > + DEBUG (( > + DEBUG_VERBOSE, > + "%a: reached FinishedApLimit=3D%u in %Lu microseconds\n", > + __FUNCTION__, > + FinishedApLimit, > + DivU64x64Remainder ( > + MultU64x32 (CpuMpData->TotalTime, 1000000), > + GetPerformanceCounterProperties (NULL, NULL), > + NULL > + ) > + )); > + } > +} > + > +/** > + Wait for AP wakeup and write AP start-up signal till AP is waken up. > + > + @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal > +**/ > +VOID > +WaitApWakeup ( > + IN volatile UINT32 *ApStartupSignalBuffer > + ) > +{ > + // > + // If AP is waken up, StartupApSignal should be cleared. > + // Otherwise, write StartupApSignal again till AP waken up. > + // > + while (InterlockedCompareExchange32 ( > + (UINT32 *)ApStartupSignalBuffer, > + WAKEUP_AP_SIGNAL, > + WAKEUP_AP_SIGNAL > + ) !=3D 0) > + { > + CpuPause (); > + } > +} > + > +/** > + This function will fill the exchange info structure. > + > + @param[in] CpuMpData Pointer to CPU MP Data > + > +**/ > +VOID > +FillExchangeInfoData ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; > + > + if (!CpuMpData->MpCpuExchangeInfo) { > + CpuMpData->MpCpuExchangeInfo =3D (MP_CPU_EXCHANGE_INFO > *)AllocatePool (sizeof (MP_CPU_EXCHANGE_INFO)); > + } > + > + ExchangeInfo =3D CpuMpData->MpCpuExchangeInfo; > + ExchangeInfo->CpuMpData =3D CpuMpData; > +} > + > +/** > + This function will be called by BSP to wakeup AP. > + > + @param[in] CpuMpData Pointer to CPU MP Data > + @param[in] Broadcast TRUE: Send broadcast IPI to all APs > + FALSE: Send IPI to AP by ApicId > + @param[in] ProcessorNumber The handle number of specified > processor > + @param[in] Procedure The function to be invoked by AP > + @param[in] ProcedureArgument The argument to be passed into AP > function > + @param[in] WakeUpDisabledAps Whether need to wake up disabled > APs in broadcast mode. Currently not used on LoongArch. > +**/ > +VOID > +WakeUpAP ( > + IN CPU_MP_DATA *CpuMpData, > + IN BOOLEAN Broadcast, > + IN UINTN ProcessorNumber, > + IN EFI_AP_PROCEDURE Procedure OPTIONAL, > + IN VOID *ProcedureArgument OPTIONAL, > + IN BOOLEAN WakeUpDisabledAps > + ) > +{ > + volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; > + UINTN Index; > + CPU_AP_DATA *CpuData; > + CPU_INFO_IN_HOB *CpuInfoInHob; > + > + CpuMpData->FinishedCount =3D 0; > + > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)CpuMpData->CpuInfoInHob; > + > + if (CpuMpData->InitFlag !=3D ApInitDone) { > + FillExchangeInfoData (CpuMpData); > + } > + > + ExchangeInfo =3D CpuMpData->MpCpuExchangeInfo; > + // > + // If InitFlag is ApInitConfig, broadcasts all APs to initize themselv= es. > + // > + if (CpuMpData->InitFlag =3D=3D ApInitConfig) { > + DEBUG ((EFI_D_INFO, "%a: func 0x%llx, ExchangeInfo 0x%llx\n", > __func__, ApWakeupFunction, (UINTN)ExchangeInfo)); > + if (CpuMpData->ApLoopMode =3D=3D ApInHltLoop) { > + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { > + if (Index !=3D CpuMpData->BspNumber) { > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_MBUF_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (IOCSR_MBUF_SEND_BOX_HI (0x3) << > IOCSR_MBUF_SEND_BOX_SHIFT) | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + ((UINTN)(ExchangeInfo) & > IOCSR_MBUF_SEND_H32_MASK)) > + ); > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_MBUF_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (IOCSR_MBUF_SEND_BOX_LO (0x3) << > IOCSR_MBUF_SEND_BOX_SHIFT) | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + ((UINTN)ExchangeInfo) << IOCSR_MBUF_SEND_BUF_SHIFT) > + ); > + > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_MBUF_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (IOCSR_MBUF_SEND_BOX_HI (0x0) << > IOCSR_MBUF_SEND_BOX_SHIFT) | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + ((UINTN)(ApWakeupFunction) & > IOCSR_MBUF_SEND_H32_MASK)) > + ); > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_MBUF_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (IOCSR_MBUF_SEND_BOX_LO (0x0) << > IOCSR_MBUF_SEND_BOX_SHIFT) | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + ((UINTN)ApWakeupFunction) << > IOCSR_MBUF_SEND_BUF_SHIFT) > + ); > + > + // > + // Send IPI 4 interrupt to wake up APs. > + // > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_IPI_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + 0x2 // Bit 2 > + ) > + ); > + } > + } > + } else { > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF3, (UINTN)ExchangeInfo); > + IoCsrWrite64 (LOONGARCH_IOCSR_MBUF0, > (UINTN)ApWakeupFunction); > + } > + > + TimedWaitForApFinish ( > + CpuMpData, > + PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1, > + PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds) > + ); > + } else { > + if (Broadcast) { > + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { > + if (Index !=3D CpuMpData->BspNumber) { > + CpuData =3D &CpuMpData->CpuData[Index]; > + if ((GetApState (CpuData) =3D=3D CpuStateDisabled) > && !WakeUpDisabledAps) { > + continue; > + } > + > + CpuData->ApFunction =3D (UINTN)Procedure; > + CpuData->ApFunctionArgument =3D (UINTN)ProcedureArgument; > + SetApState (CpuData, CpuStateReady); > + *(UINT32 *)CpuData->StartupApSignal =3D WAKEUP_AP_SIGNAL; > + > + // > + // Send IPI 4 interrupt to wake up APs. > + // > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_IPI_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (CpuInfoInHob[Index].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + 0x2 // Bit 2 > + ) > + ); > + } > + } > + > + // > + // Wait all APs waken up. > + // > + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { > + CpuData =3D &CpuMpData->CpuData[Index]; > + if (Index !=3D CpuMpData->BspNumber) { > + WaitApWakeup (CpuData->StartupApSignal); > + } > + } > + } else { > + CpuData =3D > &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->ApFunction =3D (UINTN)Procedure; > + CpuData->ApFunctionArgument =3D (UINTN)ProcedureArgument; > + SetApState (CpuData, CpuStateReady); > + // > + // Wakeup specified AP > + // > + *(UINT32 *)CpuData->StartupApSignal =3D WAKEUP_AP_SIGNAL; > + > + // > + // Send IPI 4 interrupt to wake up APs. > + // > + IoCsrWrite64 ( > + LOONGARCH_IOCSR_IPI_SEND, > + (IOCSR_MBUF_SEND_BLOCKING | > + (CpuInfoInHob[ProcessorNumber].ApicId << > IOCSR_MBUF_SEND_CPU_SHIFT) | > + 0x2 // Bit 2 > + ) > + ); > + > + // > + // Wait specified AP waken up > + // > + WaitApWakeup (CpuData->StartupApSignal); > + } > + } > +} > + > +/** > + Searches for the next waiting AP. > + > + Search for the next AP that is put in waiting state by single-threaded > StartupAllAPs(). > + > + @param[out] NextProcessorNumber Pointer to the processor number > of the next waiting AP. > + > + @retval EFI_SUCCESS The next waiting AP has been found. > + @retval EFI_NOT_FOUND No waiting AP exists. > + > +**/ > +EFI_STATUS > +GetNextWaitingProcessorNumber ( > + OUT UINTN *NextProcessorNumber > + ) > +{ > + UINTN ProcessorNumber; > + CPU_MP_DATA *CpuMpData; > + > + CpuMpData =3D GetCpuMpData (); > + > + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; > ProcessorNumber++) { > + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { > + *NextProcessorNumber =3D ProcessorNumber; > + return EFI_SUCCESS; > + } > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task > assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] ProcessorNumber The handle number of processor. > + > + @retval EFI_SUCCESS Specified AP has finished task > assigned by StartupThisAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY Specified AP has not finished task > and timeout has not expired. > +**/ > +EFI_STATUS > +CheckThisAP ( > + IN UINTN ProcessorNumber > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + CPU_AP_DATA *CpuData; > + > + CpuMpData =3D GetCpuMpData (); > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + > + // > + // If the AP finishes for StartupThisAP(), return EFI_SUCCESS. > + // > + if (GetApState (CpuData) =3D=3D CpuStateFinished) { > + if (CpuData->Finished !=3D NULL) { > + *(CpuData->Finished) =3D TRUE; > + } > + > + SetApState (CpuData, CpuStateIdle); > + return EFI_SUCCESS; > + } else { > + // > + // If timeout expires for StartupThisAP(), report timeout. > + // > + if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, > CpuData->ExpectedTime)) { > + if (CpuData->Finished !=3D NULL) { > + *(CpuData->Finished) =3D FALSE; > + } > + > + return EFI_TIMEOUT; > + } > + } > + > + return EFI_NOT_READY; > +} > + > +/** > + Checks status of all APs. > + > + This function checks whether all APs have finished task assigned by > StartupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by > StartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and > timeout has not expired. > +**/ > +EFI_STATUS > +CheckAllAPs ( > + VOID > + ) > +{ > + UINTN ProcessorNumber; > + UINTN NextProcessorNumber; > + EFI_STATUS Status; > + CPU_MP_DATA *CpuMpData; > + CPU_AP_DATA *CpuData; > + > + CpuMpData =3D GetCpuMpData (); > + > + NextProcessorNumber =3D 0; > + > + // > + // Go through all APs that are responsible for the StartupAllAPs(). > + // > + for (ProcessorNumber =3D 0; ProcessorNumber < CpuMpData->CpuCount; > ProcessorNumber++) { > + if (!CpuMpData->CpuData[ProcessorNumber].Waiting) { > + continue; > + } > + > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + // > + // Check the CPU state of AP. If it is CpuStateIdle, then the AP has > finished its task. > + // Only BSP and corresponding AP access this unit of CPU Data. This > means the AP will not modify the > + // value of state after setting the it to CpuStateIdle, so BSP can s= afely > make use of its value. > + // > + if (GetApState (CpuData) =3D=3D CpuStateFinished) { > + CpuMpData->RunningCount--; > + CpuMpData->CpuData[ProcessorNumber].Waiting =3D FALSE; > + SetApState (CpuData, CpuStateIdle); > + > + // > + // If in Single Thread mode, then search for the next waiting AP f= or > execution. > + // > + if (CpuMpData->SingleThread) { > + Status =3D GetNextWaitingProcessorNumber > (&NextProcessorNumber); > + > + if (!EFI_ERROR (Status)) { > + WakeUpAP ( > + CpuMpData, > + FALSE, > + (UINT32)NextProcessorNumber, > + CpuMpData->Procedure, > + CpuMpData->ProcArguments, > + TRUE > + ); > + } > + } > + } > + } > + > + // > + // If all APs finish, return EFI_SUCCESS. > + // > + if (CpuMpData->RunningCount =3D=3D 0) { > + return EFI_SUCCESS; > + } > + > + // > + // If timeout expires, report timeout. > + // > + if (CheckTimeout ( > + &CpuMpData->CurrentTime, > + &CpuMpData->TotalTime, > + CpuMpData->ExpectedTime > + ) > + ) > + { > + return EFI_TIMEOUT; > + } > + > + return EFI_NOT_READY; > +} > + > +/** > + Worker function to execute a caller provided function on all enabled A= Ps. > + > + @param[in] Procedure A pointer to the function to be > run on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled > APs execute > + the function specified by > Procedure one by > + one, in ascending order of > processor handle > + number. If FALSE, then all > the enabled APs > + execute the function > specified by Procedure > + simultaneously. > + @param[in] ExcludeBsp Whether let BSP also trig this > task. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en > its > + content is set to NULL. If not > all APs > + finish before timeout expires, > then its > + content is set to address of > the buffer > + holding handle numbers of > the failed APs. > + > + @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 others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +StartupAllCPUsWorker ( > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN BOOLEAN ExcludeBsp, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + CPU_MP_DATA *CpuMpData; > + UINTN ProcessorCount; > + UINTN ProcessorNumber; > + UINTN CallerNumber; > + CPU_AP_DATA *CpuData; > + BOOLEAN HasEnabledAp; > + CPU_STATE ApState; > + > + CpuMpData =3D GetCpuMpData (); > + > + if (FailedCpuList !=3D NULL) { > + *FailedCpuList =3D NULL; > + } > + > + if ((CpuMpData->CpuCount =3D=3D 1) && ExcludeBsp) { > + return EFI_NOT_STARTED; > + } > + > + if (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber !=3D CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Update AP state > + // > + CheckAndUpdateApsStatus (); > + > + ProcessorCount =3D CpuMpData->CpuCount; > + HasEnabledAp =3D FALSE; > + // > + // Check whether all enabled APs are idle. > + // If any enabled AP is not idle, return EFI_NOT_READY. > + // > + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; > ProcessorNumber++) { > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + if (ProcessorNumber !=3D CpuMpData->BspNumber) { > + ApState =3D GetApState (CpuData); > + if (ApState !=3D CpuStateDisabled) { > + HasEnabledAp =3D TRUE; > + if (ApState !=3D CpuStateIdle) { > + // > + // If any enabled APs are busy, return EFI_NOT_READY. > + // > + return EFI_NOT_READY; > + } > + } > + } > + } > + > + if (!HasEnabledAp && ExcludeBsp) { > + // > + // If no enabled AP exists and not include Bsp to do the procedure, > return EFI_NOT_STARTED. > + // > + return EFI_NOT_STARTED; > + } > + > + CpuMpData->RunningCount =3D 0; > + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; > ProcessorNumber++) { > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->Waiting =3D FALSE; > + if (ProcessorNumber !=3D CpuMpData->BspNumber) { > + if (CpuData->State =3D=3D CpuStateIdle) { > + // > + // Mark this processor as responsible for current calling. > + // > + CpuData->Waiting =3D TRUE; > + CpuMpData->RunningCount++; > + } > + } > + } > + > + CpuMpData->Procedure =3D Procedure; > + CpuMpData->ProcArguments =3D ProcedureArgument; > + CpuMpData->SingleThread =3D SingleThread; > + CpuMpData->FinishedCount =3D 0; > + CpuMpData->ExpectedTime =3D CalculateTimeout ( > + TimeoutInMicroseconds, > + &CpuMpData->CurrentTime > + ); > + CpuMpData->TotalTime =3D 0; > + CpuMpData->WaitEvent =3D WaitEvent; > + > + if (!SingleThread) { > + WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, > FALSE); > + } else { > + for (ProcessorNumber =3D 0; ProcessorNumber < ProcessorCount; > ProcessorNumber++) { > + if (ProcessorNumber =3D=3D CallerNumber) { > + continue; > + } > + > + if (CpuMpData->CpuData[ProcessorNumber].Waiting) { > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, > ProcedureArgument, TRUE); > + break; > + } > + } > + } > + > + if (!ExcludeBsp) { > + // > + // Start BSP. > + // > + Procedure (ProcedureArgument); > + } > + > + Status =3D EFI_SUCCESS; > + if (WaitEvent =3D=3D NULL) { > + do { > + Status =3D CheckAllAPs (); > + } while (Status =3D=3D EFI_NOT_READY); > + } > + > + return Status; > +} > + > +/** > + Worker function to let the caller get one enabled AP to execute a > caller-provided > + function. > + > + @param[in] Procedure A pointer to the function to be > run on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] Finished If AP returns from Procedure > before the > + timeout expires, its content > is set to TRUE. > + Otherwise, the value is set to > FALSE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP > finished before > + the timeout expires. > + @retval others Failed to Startup AP. > + > +**/ > +EFI_STATUS > +StartupThisAPWorker ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + CPU_MP_DATA *CpuMpData; > + CPU_AP_DATA *CpuData; > + UINTN CallerNumber; > + > + CpuMpData =3D GetCpuMpData (); > + > + if (Finished !=3D NULL) { > + *Finished =3D FALSE; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber !=3D CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // Check whether processor with the handle specified by > ProcessorNumber exists > + // > + if (ProcessorNumber >=3D CpuMpData->CpuCount) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Check whether specified processor is BSP > + // > + if (ProcessorNumber =3D=3D CpuMpData->BspNumber) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check parameter Procedure > + // > + if (Procedure =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Update AP state > + // > + CheckAndUpdateApsStatus (); > + > + // > + // Check whether specified AP is disabled > + // > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D > CpuStateDisabled) { > + return EFI_INVALID_PARAMETER; > + } > + > + CpuData =3D &CpuMpData->CpuData[ProcessorNumber]; > + CpuData->WaitEvent =3D WaitEvent; > + CpuData->Finished =3D Finished; > + CpuData->ExpectedTime =3D CalculateTimeout (TimeoutInMicroseconds, > &CpuData->CurrentTime); > + CpuData->TotalTime =3D 0; > + > + WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, > ProcedureArgument, FALSE); > + > + // > + // If WaitEvent is NULL, execute in blocking mode. > + // BSP checks AP's state until it finishes or TimeoutInMicrosecsond > expires. > + // > + Status =3D EFI_SUCCESS; > + if (WaitEvent =3D=3D NULL) { > + do { > + Status =3D CheckThisAP (ProcessorNumber); > + } while (Status =3D=3D EFI_NOT_READY); > + } > + > + return Status; > +} > + > +/** > + This service executes a caller provided function on all enabled CPUs. > + > + @param[in] Procedure A pointer to the function to be > run on > + enabled APs of the system. > See type > + EFI_AP_PROCEDURE. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. Zero means > + infinity. > TimeoutInMicroseconds is ignored > + for BSP. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + > + @retval EFI_SUCCESS In blocking mode, all CPUs have > finished before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has > been dispatched > + to all enabled CPUs. > + @retval EFI_DEVICE_ERROR Caller processor is AP. > + @retval EFI_NOT_READY Any enabled APs are busy. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + @retval EFI_TIMEOUT In blocking mode, the timeout > expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupAllCPUs ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL > + ) > +{ > + return StartupAllCPUsWorker ( > + Procedure, > + TRUE, > + FALSE, > + NULL, > + TimeoutInMicroseconds, > + ProcedureArgument, > + NULL > + ); > +} > + > +/** > + MP Initialize Library initialization. > + > + This service will allocate AP reset vector and wakeup all APs to do AP= s > + initialization. > + > + This service must be invoked before all other MP Initialize Library > + service are invoked. > + > + @retval EFI_SUCCESS MP initialization succeeds. > + @retval Others MP initialization fails. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibInitialize ( > + VOID > + ) > +{ > + CPU_MP_DATA *OldCpuMpData; > + CPU_INFO_IN_HOB *CpuInfoInHob; > + UINT32 MaxLogicalProcessorNumber; > + UINTN BufferSize; > + UINTN MonitorBufferSize; > + VOID *MpBuffer; > + CPU_MP_DATA *CpuMpData; > + UINTN Index; > + > + OldCpuMpData =3D GetCpuMpDataFromGuidedHob (); > + if (OldCpuMpData =3D=3D NULL) { > + MaxLogicalProcessorNumber =3D PcdGet32 > (PcdCpuMaxLogicalProcessorNumber); > + } else { > + MaxLogicalProcessorNumber =3D OldCpuMpData->CpuCount; > + } > + > + ASSERT (MaxLogicalProcessorNumber !=3D 0); > + > + MonitorBufferSize =3D sizeof (WAKEUP_AP_SIGNAL) * > MaxLogicalProcessorNumber; > + > + BufferSize =3D 0; > + BufferSize +=3D MonitorBufferSize; > + BufferSize +=3D sizeof (CPU_MP_DATA); > + BufferSize +=3D (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* > MaxLogicalProcessorNumber; > + MpBuffer =3D AllocatePages (EFI_SIZE_TO_PAGES (BufferSize)); > + ASSERT (MpBuffer !=3D NULL); > + ZeroMem (MpBuffer, BufferSize); > + > + CpuMpData =3D (CPU_MP_DATA *)MpBuffer; > + > + CpuMpData->CpuCount =3D 1; > + CpuMpData->BspNumber =3D 0; > + CpuMpData->CpuData =3D (CPU_AP_DATA *)(CpuMpData + 1); > + CpuMpData->CpuInfoInHob =3D (UINT64)(UINTN)(CpuMpData->CpuData + > MaxLogicalProcessorNumber); > + > + InitializeSpinLock (&CpuMpData->MpLock); > + > + // > + // Set BSP basic information > + // > + InitializeApData (CpuMpData, 0, 0); > + > + // > + // Set up APs wakeup signal buffer > + // > + for (Index =3D 0; Index < MaxLogicalProcessorNumber; Index++) { > + CpuMpData->CpuData[Index].StartupApSignal =3D > + (UINT32 *)((MpBuffer + BufferSize - MonitorBufferSize) + (sizeof > (WAKEUP_AP_SIGNAL) * Index)); > + } > + > + if (OldCpuMpData =3D=3D NULL) { > + if (MaxLogicalProcessorNumber > 1) { > + // > + // Wakeup all APs and calculate the processor count in system > + // > + CollectProcessorCount (CpuMpData); > + } > + } else { > + // > + // APs have been wakeup before, just get the CPU Information > + // from HOB > + // > + CpuMpData->CpuCount =3D OldCpuMpData->CpuCount; > + CpuMpData->BspNumber =3D OldCpuMpData->BspNumber; > + CpuMpData->CpuInfoInHob =3D OldCpuMpData->CpuInfoInHob; > + CpuMpData->MpCpuExchangeInfo =3D > OldCpuMpData->MpCpuExchangeInfo; > + > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)CpuMpData->CpuInfoInHob; > + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { > + InitializeSpinLock (&CpuMpData->CpuData[Index].ApLock); > + CpuMpData->CpuData[Index].CpuHealthy =3D > (CpuInfoInHob[Index].Health =3D=3D 0) ? TRUE : FALSE; > + } > + > + if (CpuMpData->CpuCount > 1) { > + // > + // Only needs to use this flag for DXE phase to update the wake up > + // buffer. Wakeup buffer allocated in PEI phase is no longer valid > + // in DXE. > + // > + CpuMpData->InitFlag =3D ApInitReconfig; > + WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE); > + > + // > + // Wait for all APs finished initialization > + // > + while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) { > + CpuPause (); > + } > + > + CpuMpData->InitFlag =3D ApInitDone; > + } > + > + if (MaxLogicalProcessorNumber > 1) { > + for (Index =3D 0; Index < CpuMpData->CpuCount; Index++) { > + SetApState (&CpuMpData->CpuData[Index], CpuStateIdle); > + } > + } > + } > + > + // > + // Initialize global data for MP support > + // > + InitMpGlobalData (CpuMpData); > + > + return EFI_SUCCESS; > +} > + > +/** > + Gets detailed MP-related information on the requested processor at the > + instant this call is made. This service may only be called from the BS= P. > + > + @param[in] ProcessorNumber The handle number of processor. > + @param[out] ProcessorInfoBuffer A pointer to the buffer where > information for > + the requested processor is > deposited. > + @param[out] HealthData Return processor health data. > + > + @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 platform. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetProcessorInfo ( > + IN UINTN ProcessorNumber, > + OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer, > + OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + UINTN CallerNumber; > + CPU_INFO_IN_HOB *CpuInfoInHob; > + > + CpuMpData =3D GetCpuMpData (); > + CpuInfoInHob =3D (CPU_INFO_IN_HOB > *)(UINTN)CpuMpData->CpuInfoInHob; > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber !=3D CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + if (ProcessorInfoBuffer =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if (ProcessorNumber >=3D CpuMpData->CpuCount) { > + return EFI_NOT_FOUND; > + } > + > + ProcessorInfoBuffer->ProcessorId =3D > (UINT64)CpuInfoInHob[ProcessorNumber].ApicId; > + ProcessorInfoBuffer->StatusFlag =3D 0; > + if (ProcessorNumber =3D=3D CpuMpData->BspNumber) { > + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_AS_BSP_BIT; > + } > + > + if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) { > + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_HEALTH_STATUS_BIT; > + } > + > + if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) =3D=3D > CpuStateDisabled) { > + ProcessorInfoBuffer->StatusFlag &=3D ~PROCESSOR_ENABLED_BIT; > + } else { > + ProcessorInfoBuffer->StatusFlag |=3D PROCESSOR_ENABLED_BIT; > + } > + > + if (HealthData !=3D NULL) { > + HealthData->Uint32 =3D CpuInfoInHob[ProcessorNumber].Health; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + This return the handle number for the calling processor. This service= may > be > + called from the BSP and APs. > + > + @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 > number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle > number was returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibWhoAmI ( > + OUT UINTN *ProcessorNumber > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + > + if (ProcessorNumber =3D=3D NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + CpuMpData =3D GetCpuMpData (); > + > + return GetProcessorNumber (CpuMpData, ProcessorNumber); > +} > + > +/** > + Retrieves the number of logical processor in the platform and the numb= er > of > + those logical processors that are enabled on this boot. This service m= ay > only > + be called from the BSP. > + > + @param[out] NumberOfProcessors Pointer to the total > number of logical > + processors in the > system, including 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 enabled > + logical processors was retrieved. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and > NumberOfEnabledProcessors > + is NULL. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibGetNumberOfProcessors ( > + OUT UINTN *NumberOfProcessors OPTIONAL, > + OUT UINTN *NumberOfEnabledProcessors OPTIONAL > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + UINTN CallerNumber; > + UINTN ProcessorNumber; > + UINTN EnabledProcessorNumber; > + UINTN Index; > + > + CpuMpData =3D GetCpuMpData (); > + > + if ((NumberOfProcessors =3D=3D NULL) && (NumberOfEnabledProcessors =3D= =3D > NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check whether caller processor is BSP > + // > + MpInitLibWhoAmI (&CallerNumber); > + if (CallerNumber !=3D CpuMpData->BspNumber) { > + return EFI_DEVICE_ERROR; > + } > + > + ProcessorNumber =3D CpuMpData->CpuCount; > + EnabledProcessorNumber =3D 0; > + for (Index =3D 0; Index < ProcessorNumber; Index++) { > + if (GetApState (&CpuMpData->CpuData[Index]) !=3D CpuStateDisabled) { > + EnabledProcessorNumber++; > + } > + } > + > + if (NumberOfProcessors !=3D NULL) { > + *NumberOfProcessors =3D ProcessorNumber; > + } > + > + if (NumberOfEnabledProcessors !=3D NULL) { > + *NumberOfEnabledProcessors =3D EnabledProcessorNumber; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Get pointer to CPU MP Data structure from GUIDed HOB. > + > + @return The pointer to CPU MP Data structure. > +**/ > +CPU_MP_DATA * > +GetCpuMpDataFromGuidedHob ( > + VOID > + ) > +{ > + EFI_HOB_GUID_TYPE *GuidHob; > + VOID *DataInHob; > + CPU_MP_DATA *CpuMpData; > + > + CpuMpData =3D NULL; > + GuidHob =3D GetFirstGuidHob (&mCpuInitMpLibHobGuid); > + > + if (GuidHob !=3D NULL) { > + DataInHob =3D GET_GUID_HOB_DATA (GuidHob); > + CpuMpData =3D (CPU_MP_DATA *)(*(UINTN *)DataInHob); > + } > + > + return CpuMpData; > +} > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h > b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h > new file mode 100644 > index 0000000000..0b071fb28d > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h > @@ -0,0 +1,361 @@ > +/** @file > + Common header file for LoongArch MP Initialize Library. > + > + Copyright (c) 2023, Loongson Technology Corporation Limited. All right= s > reserved.
> + > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef MP_LIB_H_ > +#define MP_LIB_H_ > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P') > + > +#define CPU_INIT_MP_LIB_HOB_GUID \ > + { \ > + 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0x= ad, > 0x4a } \ > + } > + > +#define PROCESSOR_RESOURCE_HOB_GUID \ > + { \ > + 0xb855c7fe, 0xa758, 0x701f, { 0xa7, 0x30, 0x87, 0xf3, 0x9c, 0x03, 0x= 46, > 0x7e } \ > + } > + > +// > +// AP loop state when APs are in idle state > +// It's value is the same with PcdCpuApLoopMode > +// > +typedef enum { > + ApInHltLoop =3D 1, > + ApInRunLoop =3D 2 > +} AP_LOOP_MODE; > + > +// > +// AP initialization state during APs wakeup > +// > +typedef enum { > + ApInitConfig =3D 1, > + ApInitReconfig =3D 2, > + ApInitDone =3D 3 > +} AP_INIT_STATE; > + > +// > +// AP state > +// > +typedef enum { > + CpuStateIdle, > + CpuStateReady, > + CpuStateBusy, > + CpuStateFinished, > + CpuStateDisabled > +} CPU_STATE; > + > +// > +// AP related data > +// > +typedef struct { > + SPIN_LOCK ApLock; > + volatile UINT32 *StartupApSignal; > + volatile UINTN ApFunction; > + volatile UINTN ApFunctionArgument; > + BOOLEAN CpuHealthy; > + volatile CPU_STATE State; > + BOOLEAN Waiting; > + BOOLEAN *Finished; > + UINT64 ExpectedTime; > + UINT64 CurrentTime; > + UINT64 TotalTime; > + EFI_EVENT WaitEvent; > +} CPU_AP_DATA; > + > +// > +// Basic CPU information saved in Guided HOB. > +// Because the contents will be shard between PEI and DXE, > +// we need to make sure the each fields offset same in different > +// architecture. > +// > +#pragma pack (1) > +typedef struct { > + UINT32 ApicId; > + UINT32 Health; > +} CPU_INFO_IN_HOB; > +#pragma pack () > + > +typedef struct _CPU_MP_DATA CPU_MP_DATA; > + > +#pragma pack(1) > + > +// > +// MP CPU exchange information for AP reset code > +// This structure is required to be packed because fixed field offsets > +// into this structure are used in assembly code in this module > +// > +typedef struct { > + CPU_MP_DATA *CpuMpData; > +} MP_CPU_EXCHANGE_INFO; > + > +#pragma pack() > + > +typedef struct { > + SPIN_LOCK Lock; > + UINT32 CpuCount; > + UINT64 CpuInfoInHob; > +} PROCESSOR_RESOURCE_DATA; > + > +// > +// CPU MP Data save in memory > +// > +struct _CPU_MP_DATA { > + UINT64 CpuInfoInHob; > + UINT32 CpuCount; > + UINT32 BspNumber; > + // > + // The above fields data will be passed from PEI to DXE > + // Please make sure the fields offset same in the different > + // architecture. > + // > + SPIN_LOCK MpLock; > + > + volatile UINT32 FinishedCount; > + UINT32 RunningCount; > + BOOLEAN SingleThread; > + EFI_AP_PROCEDURE Procedure; > + VOID *ProcArguments; > + BOOLEAN *Finished; > + UINT64 ExpectedTime; > + UINT64 CurrentTime; > + UINT64 TotalTime; > + EFI_EVENT WaitEvent; > + > + AP_INIT_STATE InitFlag; > + UINT8 ApLoopMode; > + CPU_AP_DATA *CpuData; > + volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo; > +}; > + > +extern EFI_GUID mCpuInitMpLibHobGuid; > +extern EFI_GUID mProcessorResourceHobGuid; > + > +/** > + Get the pointer to CPU MP Data structure. > + > + @return The pointer to CPU MP Data structure. > +**/ > +CPU_MP_DATA * > +GetCpuMpData ( > + VOID > + ); > + > +/** > + Save the pointer to CPU MP Data structure. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure will be > saved. > +**/ > +VOID > +SaveCpuMpData ( > + IN CPU_MP_DATA *CpuMpData > + ); > + > +/** > + This function will be called by BSP to wakeup AP. > + > + @param[in] CpuMpData Pointer to CPU MP Data > + @param[in] Broadcast TRUE: Send broadcast IPI to all APs > + FALSE: Send IPI to AP by ApicId > + @param[in] ProcessorNumber The handle number of specified > processor > + @param[in] Procedure The function to be invoked by AP > + @param[in] ProcedureArgument The argument to be passed into AP > function > + @param[in] WakeUpDisabledAps Whether need to wake up disabled > APs in broadcast mode. > +**/ > +VOID > +WakeUpAP ( > + IN CPU_MP_DATA *CpuMpData, > + IN BOOLEAN Broadcast, > + IN UINTN ProcessorNumber, > + IN EFI_AP_PROCEDURE Procedure OPTIONAL, > + IN VOID *ProcedureArgument OPTIONAL, > + IN BOOLEAN WakeUpDisabledAps > + ); > + > +/** > + Initialize global data for MP support. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure. > +**/ > +VOID > +InitMpGlobalData ( > + IN CPU_MP_DATA *CpuMpData > + ); > + > +/** > + Worker function to execute a caller provided function on all enabled A= Ps. > + > + @param[in] Procedure A pointer to the function to be > run on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled > APs execute > + the function specified by > Procedure one by > + one, in ascending order of > processor handle > + number. If FALSE, then all > the enabled APs > + execute the function > specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] FailedCpuList If all APs finish successfully, th= en > its > + content is set to NULL. If not > all APs > + finish before timeout expires, > then its > + content is set to address of > the buffer > + holding handle numbers of > the failed APs. > + > + @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 others Failed to Startup all APs. > + > +**/ > +EFI_STATUS > +StartupAllCPUsWorker ( > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN BOOLEAN ExcludeBsp, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ); > + > +/** > + Worker function to let the caller get one enabled AP to execute a > caller-provided > + function. > + > + @param[in] Procedure A pointer to the function to be > run on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. > + @param[in] ProcedureArgument The parameter passed into > Procedure for > + all APs. > + @param[out] Finished If AP returns from Procedure > before the > + timeout expires, its content > is set to TRUE. > + Otherwise, the value is set to > FALSE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP > finished before > + the timeout expires. > + @retval others Failed to Startup AP. > + > +**/ > +EFI_STATUS > +StartupThisAPWorker ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ); > + > +/** > + Worker function to let the caller enable or disable an AP from this po= int > onward. > + This service may only be called from the BSP. > + This instance will be added in the future. > + > + @param[in] ProcessorNumber The handle number of AP. > + @param[in] EnableAP Specifies the new state for the > processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that > specifies > + the new health status of the AP. > + > + @retval EFI_SUCCESS The specified AP was enabled or > disabled successfully. > + @retval others Failed to Enable/Disable AP. > + > +**/ > +EFI_STATUS > +EnableDisableApWorker ( > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ); > + > +/** > + Get pointer to CPU MP Data structure from GUIDed HOB. > + > + @return The pointer to CPU MP Data structure. > +**/ > +CPU_MP_DATA * > +GetCpuMpDataFromGuidedHob ( > + VOID > + ); > + > +/** Checks status of specified AP. > + > + This function checks whether the specified AP has finished the task > assigned > + by StartupThisAP(), and whether timeout expires. > + > + @param[in] ProcessorNumber The handle number of processor. > + > + @retval EFI_SUCCESS Specified AP has finished task > assigned by StartupThisAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY Specified AP has not finished task > and timeout has not expired. > +**/ > +EFI_STATUS > +CheckThisAP ( > + IN UINTN ProcessorNumber > + ); > + > +/** > + Checks status of all APs. > + > + This function checks whether all APs have finished task assigned by > StartupAllAPs(), > + and whether timeout expires. > + > + @retval EFI_SUCCESS All APs have finished task assigned by > StartupAllAPs(). > + @retval EFI_TIMEOUT The timeout expires. > + @retval EFI_NOT_READY APs have not finished task and > timeout has not expired. > +**/ > +EFI_STATUS > +CheckAllAPs ( > + VOID > + ); > + > +/** > + Checks APs status and updates APs status if needed. > + > +**/ > +VOID > +CheckAndUpdateApsStatus ( > + VOID > + ); > + > +/** > + Enable Debug Agent to support source debugging on AP function. > + This instance will added in the future. > + > +**/ > +VOID > +EnableDebugAgent ( > + VOID > + ); > + > +#endif > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > new file mode 100644 > index 0000000000..4b2a5454c1 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > @@ -0,0 +1,37 @@ > +## @file > +# LoongArch64 MP initialize support functions for PEI phase. > +# > +# Copyright (c) 2023, Loongson Technology Corporation Limited. All righ= ts > reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 1.29 > + BASE_NAME =3D PeiMpInitLib > + MODULE_UNI_FILE =3D PeiMpInitLib.uni > + FILE_GUID =3D > ED078F16-A2D3-2F34-9267-E24D56E91FCF > + MODULE_TYPE =3D PEIM > + VERSION_STRING =3D 1.1 > + LIBRARY_CLASS =3D MpInitLib|PEIM > + > +[Sources.common] > + PeiMpLib.c > + MpLib.c > + MpLib.h > + > +[Packages] > + MdePkg/MdePkg.dec > + UefiCpuPkg/UefiCpuPkg.dec > + > +[LibraryClasses] > + BaseLib > + CpuLib > + HobLib > + MemoryAllocationLib > + SynchronizationLib > + TimerLib > + > +[Pcd] > + gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber > ## CONSUMES > + gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds > ## CONSUMES > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni > b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni > new file mode 100644 > index 0000000000..f22f09523d > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.uni > @@ -0,0 +1,15 @@ > +// /** @file > +// MP Initialize Library instance for PEI driver. > +// > +// MP Initialize Library instance for PEI driver. > +// > +// Copyright (c) 2023, Loongson Technology Corporation Limited. All righ= ts > reserved.
> +// > +// SPDX-License-Identifier: BSD-2-Clause-Patent > +// > +// **/ > + > + > +#string STR_MODULE_ABSTRACT #language en-US "MP > Initialize Library instance for PEI driver." > + > +#string STR_MODULE_DESCRIPTION #language en-US "MP > Initialize Library instance for PEI driver." > diff --git a/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c > b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c > new file mode 100644 > index 0000000000..80938599b3 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c > @@ -0,0 +1,404 @@ > +/** @file > + LoongArch64 MP initialize support functions for PEI phase. > + > + Copyright (c) 2023, Loongson Technology Corporation Limited. All right= s > reserved.
> + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include "MpLib.h" > + > +/** > + Enable Debug Agent to support source debugging on AP function. > + > +**/ > +VOID > +EnableDebugAgent ( > + VOID > + ) > +{ > +} > + > +/** > + Get pointer to CPU MP Data structure. > + > + @return The pointer to CPU MP Data structure. > +**/ > +CPU_MP_DATA * > +GetCpuMpData ( > + VOID > + ) > +{ > + CPU_MP_DATA *CpuMpData; > + > + CpuMpData =3D GetCpuMpDataFromGuidedHob (); > + ASSERT (CpuMpData !=3D NULL); > + return CpuMpData; > +} > + > +/** > + Save the pointer to CPU MP Data structure. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure will be > saved. > +**/ > +VOID > +SaveCpuMpData ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + UINT64 Data64; > + > + // > + // Build location of CPU MP DATA buffer in HOB > + // > + Data64 =3D (UINT64)(UINTN)CpuMpData; > + BuildGuidDataHob ( > + &mCpuInitMpLibHobGuid, > + (VOID *)&Data64, > + sizeof (UINT64) > + ); > +} > + > +/** > + Save the Processor Resource Data. > + > + @param[in] ResourceData The pointer to Processor Resource Data > structure will be saved. > +**/ > +VOID > +SaveProcessorResourceData ( > + IN PROCESSOR_RESOURCE_DATA *ResourceData > + ) > +{ > + UINT64 Data64; > + > + // > + // Build location of Processor Resource Data buffer in HOB > + // > + Data64 =3D (UINT64)(UINTN)ResourceData; > + BuildGuidDataHob ( > + &mProcessorResourceHobGuid, > + (VOID *)&Data64, > + sizeof (UINT64) > + ); > +} > + > +/** > + Get available EfiBootServicesCode memory below 4GB by specified size. > + > + This buffer is required to safely transfer AP from real address mode t= o > + protected mode or long mode, due to the fact that the buffer returned = by > + GetWakeupBuffer() may be marked as non-executable. > + > + @param[in] BufferSize Wakeup transition buffer size. > + > + @retval other Return wakeup transition buffer address below 4GB. > + @retval 0 Cannot find free memory below 4GB. > +**/ > +UINTN > +GetModeTransitionBuffer ( > + IN UINTN BufferSize > + ) > +{ > + // > + // PEI phase doesn't need to do such transition. So simply return 0. > + // > + return 0; > +} > + > +/** > + Checks APs status and updates APs status if needed. > + > +**/ > +VOID > +CheckAndUpdateApsStatus ( > + VOID > + ) > +{ > +} > + > +/** > + Initialize global data for MP support. > + > + @param[in] CpuMpData The pointer to CPU MP Data structure. > +**/ > +VOID > +InitMpGlobalData ( > + IN CPU_MP_DATA *CpuMpData > + ) > +{ > + SaveCpuMpData (CpuMpData); > +} > + > +/** > + This service executes a caller provided function on all enabled APs. > + > + @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 execute > + the function specified by > Procedure one by > + one, in ascending order of > processor handle > + number. If FALSE, then all > the enabled APs > + execute the function > specified by Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. If it is NULL, then > execute in > + blocking mode. BSP waits > until all APs finish > + or TimeoutInMicroSeconds > expires. If it's > + not NULL, then execute in > non-blocking mode. > + BSP requests the function > specified by > + Procedure to be started on > all the enabled > + APs, and go on executing > immediately. If > + all return from Procedure, or > TimeoutInMicroSeconds > + expires, this event is signaled. > The BSP > + can use the CheckEvent() or > WaitForEvent() > + services to check the state of > event. Type > + EFI_EVENT is defined in > CreateEvent() in > + the Unified Extensible > Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, > either for > + blocking or non-blocking > mode. Zero means > + infinity. If the timeout > expires before > + all APs return from > Procedure, then Procedure > + on the failed APs is > terminated. All enabled > + APs are available for next > function assigned > + by MpInitLibStartupAllAPs() > or > + MPInitLibStartupThisAP(). > + If the timeout expires in > blocking mode, > + BSP returns EFI_TIMEOUT. > If the timeout > + expires in non-blocking mode, > WaitEvent > + 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 APs > + finish before timeout expires, > then its > + content is set to address of > the buffer > + holding handle numbers of > the failed APs. > + The buffer is allocated by MP > Initialization > + library, and it's the caller's > responsibility to > + free the buffer with > FreePool() service. > + In blocking mode, it is ready > for consumption > + when the call returns. In > non-blocking mode, > + it is ready when WaitEvent is > signaled. 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 after the > + UEFI event > EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_UNSUPPORTED WaitEvent is not NULL if > non-blocking mode is not > + supported. > + @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_NOT_READY MP Initialize Library is not > initialized. > + @retval EFI_TIMEOUT In blocking mode, the timeout > expired before > + all enabled APs have finished. > + @retval EFI_INVALID_PARAMETER Procedure is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibStartupAllAPs ( > + IN EFI_AP_PROCEDURE Procedure, > + IN BOOLEAN SingleThread, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT UINTN **FailedCpuList OPTIONAL > + ) > +{ > + if (WaitEvent !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + return StartupAllCPUsWorker ( > + Procedure, > + SingleThread, > + TRUE, > + NULL, > + TimeoutInMicroseconds, > + ProcedureArgument, > + FailedCpuList > + ); > +} > + > +/** > + This service lets the caller get one enabled AP to execute a caller-pr= ovided > + function. > + > + @param[in] Procedure A pointer to the function to be > run on the > + designated AP of the system. > See type > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. > The range is > + from 0 to the total number of > logical > + processors minus 1. The > total number of > + logical processors can be > retrieved by > + > MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the > caller with CreateEvent() > + service. If it is NULL, then > execute in > + blocking mode. BSP waits > until this AP finish > + or TimeoutInMicroSeconds > expires. If it's > + not NULL, then execute in > non-blocking 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 > TimeoutInMicroSeconds > + expires, this event is signaled. > The BSP > + can use the CheckEvent() or > WaitForEvent() > + services to check the state of > event. Type > + EFI_EVENT is defined in > CreateEvent() in > + the Unified Extensible > Firmware Interface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + this AP to finish this > Procedure, either for > + blocking or non-blocking > mode. Zero means > + infinity. If the timeout > expires before > + this AP returns from > Procedure, then Procedure > + on the AP is terminated. The > + AP is available for next > function assigned > + by MpInitLibStartupAllAPs() > or > + MpInitLibStartupThisAP(). > + If the timeout expires in > blocking mode, > + BSP returns EFI_TIMEOUT. > If the timeout > + expires in non-blocking mode, > WaitEvent > + 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 ignored. > + In non-blocking mode, if AP > returns from > + Procedure before the > timeout expires, its > + content is set to TRUE. > Otherwise, the > + value is set to FALSE. The > caller can > + determine if the AP returned > from Procedure > + 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 been > + dispatched to specified AP. > + @retval EFI_UNSUPPORTED A non-blocking mode request was > made after the > + UEFI event > EFI_EVENT_GROUP_READY_TO_BOOT was > + signaled. > + @retval EFI_UNSUPPORTED WaitEvent is not NULL if > non-blocking mode is not > + supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_TIMEOUT In blocking mode, the timeout > expired before > + the specified AP has finished. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + @retval EFI_NOT_FOUND The processor with the handle > specified by > + 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 > +MpInitLibStartupThisAP ( > + IN EFI_AP_PROCEDURE Procedure, > + IN UINTN ProcessorNumber, > + IN EFI_EVENT WaitEvent OPTIONAL, > + IN UINTN TimeoutInMicroseconds, > + IN VOID *ProcedureArgument OPTIONAL, > + OUT BOOLEAN *Finished OPTIONAL > + ) > +{ > + if (WaitEvent !=3D NULL) { > + return EFI_UNSUPPORTED; > + } > + > + return StartupThisAPWorker ( > + Procedure, > + ProcessorNumber, > + NULL, > + TimeoutInMicroseconds, > + ProcedureArgument, > + Finished > + ); > +} > + > +/** > + This service switches the requested AP to be the BSP from that point > onward. > + This service changes the BSP for all purposes. This call can only be > performed > + by the current BSP. > + > + @param[in] ProcessorNumber The handle number of AP that is to > become the new > + BSP. The range is from 0 to the total > number of > + logical processors minus 1. The total > number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @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 prior 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 BSP or > + a disabled AP. > + @retval EFI_NOT_READY The specified AP is busy. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibSwitchBSP ( > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableOldBSP > + ) > +{ > + return EFI_UNSUPPORTED; > +} > + > +/** > + This service lets the caller enable or disable an AP from this point o= nward. > + This service may only be called from the BSP. > + > + @param[in] ProcessorNumber The handle number of AP. > + The range is from 0 to the total > number of > + logical processors minus 1. The total > number of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + @param[in] EnableAP Specifies the new state for the > processor for > + enabled, FALSE for disabled. > + @param[in] HealthFlag If not NULL, a pointer to a value that > specifies > + 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. All other > + bits are ignored. If it is NULL, this > parameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or > disabled successfully. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot > be completed > + prior to this service returning. > + @retval EFI_UNSUPPORTED Enabling or disabling an AP is not > supported. > + @retval EFI_DEVICE_ERROR The calling processor is an AP. > + @retval EFI_NOT_FOUND Processor with the handle > specified by ProcessorNumber > + does not exist. > + @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the > BSP. > + @retval EFI_NOT_READY MP Initialize Library is not > initialized. > + > +**/ > +EFI_STATUS > +EFIAPI > +MpInitLibEnableDisableAP ( > + IN UINTN ProcessorNumber, > + IN BOOLEAN EnableAP, > + IN UINT32 *HealthFlag OPTIONAL > + ) > +{ > + return EFI_UNSUPPORTED; > +} > diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc > index 709992d327..da49031877 100644 > --- a/UefiCpuPkg/UefiCpuPkg.dsc > +++ b/UefiCpuPkg/UefiCpuPkg.dsc > @@ -211,6 +211,8 @@ >=20 > UefiCpuPkg/Library/LoongArch64CpuExceptionHandlerLib/DxeCpuException > HandlerLib.inf > UefiCpuPkg/Library/LoongArch64CpuMmuLib/PeiCpuMmuLib.inf > UefiCpuPkg/Library/LoongArch64CpuMmuLib/DxeCpuMmuLib.inf > + UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > + UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf >=20 > [BuildOptions] > *_*_*_CC_FLAGS =3D -D DISABLE_NEW_DEPRECATED_INTERFACES > -- > 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 (#112697): https://edk2.groups.io/g/devel/message/112697 Mute This Topic: https://groups.io/mt/103129100/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/19134562= 12/xyzzy [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-