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 D8E84740047 for ; Fri, 12 Jan 2024 08:50:37 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=NyqGQjC40HPzj++JteUKoY29+rOq0Ol35g8ftD98oIY=; 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=1705049436; v=1; b=di83E374urkI5adqZx2iI9YYxqOr+7gShRpO1spxhh1gYHW9/4QYJawYqtATc35SM8/Gmzu1 RriwHCYjVikSFT9qtWoPVEfpxPSkm0QoavmCEMJzdwN6dCt7NPufHX/WES6HLLRF/oZuHHf2h4B YFl1uTMUfHQ3mWQ+TDNDmlEk= X-Received: by 127.0.0.2 with SMTP id PZ4aYY7687511xm7LhP1r3nO; Fri, 12 Jan 2024 00:50:36 -0800 X-Received: from mgamail.intel.com (mgamail.intel.com [192.55.52.88]) by mx.groups.io with SMTP id smtpd.web10.3388.1705049435982673662 for ; Fri, 12 Jan 2024 00:50:36 -0800 X-IronPort-AV: E=McAfee;i="6600,9927,10950"; a="430295392" X-IronPort-AV: E=Sophos;i="6.04,189,1695711600"; d="scan'208";a="430295392" X-Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jan 2024 00:50:35 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10950"; a="782964519" X-IronPort-AV: E=Sophos;i="6.04,189,1695711600"; d="scan'208";a="782964519" X-Received: from orsmsx602.amr.corp.intel.com ([10.22.229.15]) by orsmga002.jf.intel.com with ESMTP/TLS/AES256-GCM-SHA384; 12 Jan 2024 00:50:34 -0800 X-Received: from orsmsx611.amr.corp.intel.com (10.22.229.24) 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; Fri, 12 Jan 2024 00:50:34 -0800 X-Received: from orsmsx610.amr.corp.intel.com (10.22.229.23) by ORSMSX611.amr.corp.intel.com (10.22.229.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Fri, 12 Jan 2024 00:50:34 -0800 X-Received: from ORSEDG602.ED.cps.intel.com (10.7.248.7) by orsmsx610.amr.corp.intel.com (10.22.229.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35 via Frontend Transport; Fri, 12 Jan 2024 00:50:34 -0800 X-Received: from NAM10-BN7-obe.outbound.protection.outlook.com (104.47.70.101) by edgegateway.intel.com (134.134.137.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Fri, 12 Jan 2024 00:50:33 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RLWFo6yW0lTyiMxJuC1l3yen1EJzwJLB0fZuMJD616XA0OmIjbN0aOqh0i3D0aws+WBpj0/UzwqqkGo/exkyXyGqsMB/MsI45H46pqmZtiifP7iTkWqDKppD7iqQSt5S64ANYDv0IgejB9AZwhjrgwkGzwVShaJSxzVgVxY+/fav6+PwGV2pz1hCCCHHsSpCTVTqBtQFTZOV2e2iweR8c7DwTNMAGu3MfWiLq6+AES3mtRKnt4zt1A12z2HIBQTSljLuk7kBWdKIVGzU5NR5F4qqJ+1ME2phk1kSj0tFbVq4SB5UzLIafj2VHjlUs/bPeeoJFw3y4VjhapMaCsLe3w== 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=RstwRamfscApY2kDwimDIma+1NPWJdkTzgUr0HEeWq0=; b=UZgZjZ2wtUTRqAXhX+nM/5lBT/zbfm1EhBjyGb0e4Fz0Y79ZUTwBro6tx9Pe/baTxaIzRyiNdj6XngvkdX2XMsMA3oM4rSw4NmVcAC4/mKQQGzzHGlGA2R+X7AVSqZStsulSfisHTE0zW5APIcFwaDbhcRBos1smJlwlIxJyDvzhtWsxiq2CfbuwXtXhHGEo0yyIImRsujZlfgJKg4giFK7OLPUVDdOPZyBTqLjWzdkCeXMcBQWLzEGtWWo2jEw80jW4aKupCRWzbys2KXfRcmndRpc4E4yjda3iY/a2VA40YqMMSh0RDxwIy/K0K8lrGgdzoEs1QPvYoYBZ7aY0TA== 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 MW4PR11MB6569.namprd11.prod.outlook.com (2603:10b6:303:1e1::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7181.19; Fri, 12 Jan 2024 08:50:28 +0000 X-Received: from MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::3fea:ca2b:2ef7:e3d4]) by MN6PR11MB8244.namprd11.prod.outlook.com ([fe80::3fea:ca2b:2ef7:e3d4%4]) with mapi id 15.20.7159.020; Fri, 12 Jan 2024 08:50:28 +0000 From: "Ni, Ray" To: "devel@edk2.groups.io" , "lichao@loongson.cn" CC: "Dong, Eric" , "Kumar, Rahul R" , Gerd Hoffmann Subject: Re: [edk2-devel] [PATCH v7 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Thread-Topic: [edk2-devel] [PATCH v7 15/37] UefiCpuPkg: Add multiprocessor library for LoongArch64 Thread-Index: AQHaRTDayL0ZpD0nO02dxiLFtdzk1bDV3kzQ Date: Fri, 12 Jan 2024 08:50:28 +0000 Message-ID: References: <20240112082153.3284189-1-lichao@loongson.cn> <20240112082424.3288864-1-lichao@loongson.cn> In-Reply-To: <20240112082424.3288864-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_|MW4PR11MB6569:EE_ x-ms-office365-filtering-correlation-id: 588b8f2b-5958-43ca-3556-08dc134b86fa x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: rK1L0em58hgDrGXqA2fIIAPmpOF2xnqxkC8ociD1gzE7EK2JFxAbfkFBDk1dNUdBZoDT2+Vru2bhsXCKXZEhycWXLAb/mMtFUmt8Ppc3YtUUD+5k53nfoa635ZKB4Lv35nWjTdVi1QMXgYfqSBld3GOwyl/E9O3Zfkv2ABC319jnhRFZljZH1kfdc3bMSk4VILKM/2wl2g+sxvkP3FiUjCNjVN1buQpPWpu4ty1Lg6JgB3fwsB0mEF+wjApf/q3oWhIF9r45PX5SyB5Wf/Dwlw4QKVuD5kIsEZ4Men2m1AyCgoIn/M3KoZfqX04G3wlCIGHbvQITIK394iq/5oNjUYdv/bQL4aIRYZAf9eiEfeQuo/9MvyMnRfdJqpf2oO/INWyZxVG33Ji4QfAnXRZaFq5hTKpTiU5XPYcZygm6dqftLkGaTYV77z1L997dwqKhES2oWhqosqeho6LwLxIQpRfCLBqrQWtHn9CVbshYQIzzi1Kb2OSUsDs8H612HOXBU6xNuf90hp60VpHM2DG1VnmeqxefnOQ1vdGLIVanW9EgDsvEnNIE49yrerO4GKyQJD08C/dhP680qKarAZWpf28t2rzfWXlDGKp+d8v546m2X8sMdSPn20X2609c3W/nR5Nb48RgfIdBE13CF1wjqg== x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?1FU1VLexWcpoqD3h/lubWGNanPw1i4WH6NinOFHHiMHwjdJWOTG4AVwnf1V9?= =?us-ascii?Q?btFVzE7i6I83z4d43FgE1Wl+35xdEERF8sdoP6g6tNJW6i8XSsRA1yv6X/z5?= =?us-ascii?Q?c05cbgCGjeg+BeUr7dbID/nuL7nmVIIrxV8+sYaEOwIaAB2ajOQjl3vnWpiO?= =?us-ascii?Q?T/KxdL4jF1fHN/bv1w9PRaxQEDEeDiTPmDYW9T5oM6dG6S0t86GhljA40GVX?= =?us-ascii?Q?yFELp2Dbgx0xOrF4Y6Tz/3irUf32XHx0HYsuwEwDuoePHgWO04x22O7rFhYk?= =?us-ascii?Q?E3pdczolm4Zj9RfKI4sAKlCF07VfH+Y5m3tx3s5tCxV8Irveu7OcUYnAMt1h?= =?us-ascii?Q?r6EoiqaWxCUQ8m9j2JYjkfeuobCqDSgrrlC5l529uyaDZlaX7hcG/PaWMnKl?= =?us-ascii?Q?5RnnY3y6opk9L9xFcmVRDTUlANz2DYJXTEpABePkDQYgOlKPqqxmuG+Mjb3n?= =?us-ascii?Q?f96pnVRh9oRRD5gRd32bwFmanW1Xt47BpFJv6h+Se8hIWLRjKGKS8V+MEyto?= =?us-ascii?Q?mAt7T0DRBAmCD30SBD+Q9PeZ9HhRzFo/j1FuLFqJPZCyIEJdl7XVgiMF7rsH?= =?us-ascii?Q?Pl7dOZLyG0aKRogjx/D0QkaqhrOhcQO3iW6ZKors752JfC4X8p05NziZmrlx?= =?us-ascii?Q?VW7T43fkWLs1AdMCSd487WwJAD6DjWT7L7iDav2U+hbm8IjRnD9jFaWG0rA9?= =?us-ascii?Q?uorpWaRgTE5xF3IzcFAgjzjfo+YCqyRHxPT1hWYssKNvF1v6/r1l/XJQ7nlG?= =?us-ascii?Q?jIcNVbnGK0XU5CoJQY1pJrzIJTGiDV6iDTzrJGEFZzUCgFUlGvVjHXBOJM5m?= =?us-ascii?Q?fz8M+We3ytNWxBgk3PbUlCMWHPJZOZMvjrG+QThfOSl0vPOHUAmwMXEgQdQz?= =?us-ascii?Q?Lt/h48AZS6f9rjWnMKv2MDPmhW3d5jGSQmHEMbrM6GWlmaZEoxoHHlW7bEEV?= =?us-ascii?Q?oNY5varUszdiiQqanzREyalaUK2Gzs3kNL6fsiZne5xV10whDrMg3d9+vv2y?= =?us-ascii?Q?5vOwDkwFVeyxT0rBW8ByN2DU2w+uM4pznTOK3fJaefNNlP+Gmp/lWO5qPLpg?= =?us-ascii?Q?0SumtscLMH0cKaHwr1fNrRG42pjhtdjmDrnf/nrUfbc4MF8rrrqnOIa9zMFT?= =?us-ascii?Q?QJlYgV7n/Vr7bOShe3UxMVvClzmRmYmNJY6CoZduW+CzUeArgAkpSmwXQg3u?= =?us-ascii?Q?KKg0PP3JyL+Sy8cfBINP0Q0SvQ9w0bnL6xhxktqSGAxmzcUcHgEDv9/JuYvM?= =?us-ascii?Q?WWARJtkKnYdKgvhHdVSFeufgT2IhDkgDd2HKEhRN4Ic6aU9bhZiZEfy+iNQ1?= =?us-ascii?Q?ATlNkKxlz42dXnA5Kr0+uiw7+iMNmsXdkiqqlksZ40zuvvSNWPSj4RzbYFzk?= =?us-ascii?Q?M942GPrap2sosWv8/Wk9v7oC81mzg2/EauBxuAd/F8Qv6/SvY3NuQhKL/7Ew?= =?us-ascii?Q?V9wO7mnIudj+XigT4U0BqLLaqZw1s0NYlqWveDB5xkWIkpp/LbdEU/zC6gCS?= =?us-ascii?Q?CIdi5DcsiGJwFOiZjY5Kv6Ra3qSqe0aed1x68f+Oy24aAZ4c4xOS+ekPYqs8?= =?us-ascii?Q?U110G7rQ0SWnnjYJR7g=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: 588b8f2b-5958-43ca-3556-08dc134b86fa X-MS-Exchange-CrossTenant-originalarrivaltime: 12 Jan 2024 08:50:28.7243 (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: VwIS2uqxI7laB7BDOyWX6T41FOFK19wAZlgmeaZmEtqK6NVceK8nCGb0dJ/KQ9Mp1YHXIxJ0Xi/dSA/Ey8OM5w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR11MB6569 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: dQYO9WDKSkcpIYkRJJ9GVB9vx7686176AA= 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=di83E374; 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}") Chao, Do you mind putting the lib content under UefiCpuPkg/Library/MpInitLib/Loon= gArch64/? It also follows the guidelines and avoid creating too many folders under Li= brary folder. Thanks, Ray > -----Original Message----- > From: devel@edk2.groups.io On Behalf Of Chao Li > Sent: Friday, January 12, 2024 4:24 PM > To: devel@edk2.groups.io > Cc: Dong, Eric ; Ni, Ray ; Kumar, > Rahul R ; Gerd Hoffmann > Subject: [edk2-devel] [PATCH v7 15/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..519af41209 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpInitLib.inf > @@ -0,0 +1,45 @@ > +## @file > +# LoongArch64 MP initialize support functions for DXE phase. > +# > +# Copyright (c) 2024, 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-7982B6EA293= 1 > + 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..c1c67291a6 > --- /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) 2024, 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..739da77e32 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/DxeMpLib.c > @@ -0,0 +1,480 @@ > +/** @file > + LoongArch64 MP initialize support functions for DXE phase. > + > + Copyright (c) 2024, 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until all= APs finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on all the= enabled > + APs, and go on executing immediate= ly. If > + all return from Procedure, or Time= outInMicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + all APs return from Procedure, the= n Procedure > + on the failed APs is terminated. A= ll enabled > + APs are available for next functio= n assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e > for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored= . > Otherwise, > + if all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + The buffer is allocated by MP Init= ialization > + library, and it's the caller's res= ponsibility to > + free the buffer with FreePool() se= rvice. > + In blocking mode, it is ready for = consumption > + when the call returns. In non-bloc= king mode, > + it is ready when WaitEvent is sign= aled. The > + list of failed CPU is terminated b= y > + END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > dispatched > + to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made > after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @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 ru= n on the > + designated AP of the system. See t= ype > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The r= ange > is > + from 0 to the total number of logi= cal > + processors minus 1. The total numb= er of > + logical processors can be retrieve= d by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until thi= s AP finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on this AP= , > + and go on executing immediately. I= f this AP > + return from Procedure or TimeoutIn= MicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + this AP to finish this Procedure, = either for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + this AP returns from Procedure, th= en 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 t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e > on the > + specified AP. > + @param[out] Finished If NULL, this parameter is ignored= . In > + blocking mode, this parameter is i= gnored. > + In non-blocking mode, if AP return= s from > + Procedure before the timeout expir= es, 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 finishe= d 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_BO= OT 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 initializ= ed. > + @retval EFI_NOT_FOUND The processor with the handle specifie= d 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 p= erformed > + 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 num= ber of > + logical processors minus 1. The total num= ber 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 disable= d. > + > + @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 specifie= d 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 initializ= ed. > + > +**/ > +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 o= f > + logical processors minus 1. The total num= ber 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 sp= ecifies > + the new health status of the AP. This fla= g > + 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 pa= rameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabl= ed > 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 initializ= ed. > + > +**/ > +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..edc2670dca > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.c > @@ -0,0 +1,1596 @@ > +/** @file > + LoongArch64 CPU MP Initialize Library common functions. > + > + Copyright (c) 2024, 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 (BIT12); > + IoCsrWrite32 (LOONGARCH_IOCSR_IPI_EN, 0xFFFFFFFFU); > + 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 val= ue. > + > + 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 rec= ognized > + // 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 performanc= e > counter > + when it was last read. > + On output, the current value of the pe= rformance > + counter > + @param[in] TotalTime The total amount of elapsed time in > performance > + counter ticks. > + @param[in] Timeout The number of performance counter tick= s > required > + to reach a timeout condition. > + > + @retval TRUE A timeout condition has been reached. > + @retval FALSE A timeout condition has not been reach= ed. > + > +**/ > +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 spe= cified > + 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", > + __func__, > + 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 ((DEBUG_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[ProcessorNumbe= r]; > + 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 as= signed > + 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 t= imeout > 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 h= as > 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 ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] ExcludeBsp Whether let BSP also trig this tas= k. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e > 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, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > 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 call= er- > provided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e > for > + all APs. > + @param[out] Finished If AP returns from Procedure befor= e the > + timeout expires, its content is se= t to TRUE. > + Otherwise, the value is set to FAL= SE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finishe= d 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 ProcessorNumbe= r > 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 ex= pires. > + // > + 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. TimeoutInMicroseconds is= ignored > + for BSP. > + @param[in] ProcedureArgument The parameter passed into Procedur= e > for > + all APs. > + > + @retval EFI_SUCCESS In blocking mode, all CPUs have finish= ed before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > 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 initializ= ed. > + @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].Heal= th > =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 specifie= d by > + ProcessorNumber does not exist in the = platform. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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 o= f > + logical processors minus 1. The total num= ber of > + logical processors can be retrieved by > + MpInitLibGetNumberOfProcessors(). > + > + @retval EFI_SUCCESS The current processor handle number wa= s > returned > + in ProcessorNumber. > + @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. > + @retval EFI_NOT_READY MP Initialize Library is not initializ= ed. > + > +**/ > +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, incl= uding the BSP > + and disabled APs. > + @param[out] NumberOfEnabledProcessors Pointer to the number of > enabled logical > + processors that exist in syste= m, including > + the BSP. > + > + @retval EFI_SUCCESS The number of logical processors and e= nabled > + 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 initializ= ed. > + > +**/ > +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..ae5f63d267 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/MpLib.h > @@ -0,0 +1,361 @@ > +/** @file > + Common header file for LoongArch MP Initialize Library. > + > + Copyright (c) 2024, 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 ru= n on > + enabled APs of the system. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e > 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, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > 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 call= er- > provided > + function. > + > + @param[in] Procedure A pointer to the function to be ru= n on > + enabled APs of the system. > + @param[in] ProcessorNumber The handle number of the AP. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. > + @param[in] ProcedureArgument The parameter passed into Procedur= e > for > + all APs. > + @param[out] Finished If AP returns from Procedure befor= e the > + timeout expires, its content is se= t to TRUE. > + Otherwise, the value is set to FAL= SE. > + > + @retval EFI_SUCCESS In blocking mode, specified AP finishe= d 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 sp= ecifies > + 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 as= signed > + 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 t= imeout > 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 h= as > 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..7ecda0cce8 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpInitLib.inf > @@ -0,0 +1,37 @@ > +## @file > +# LoongArch64 MP initialize support functions for PEI phase. > +# > +# Copyright (c) 2024, 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-E24D56E91FC= F > + 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..51fdc618c6 > --- /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) 2024, 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..d1c5e55b57 > --- /dev/null > +++ b/UefiCpuPkg/Library/LoongArch64MpInitLib/PeiMpLib.c > @@ -0,0 +1,404 @@ > +/** @file > + LoongArch64 MP initialize support functions for PEI phase. > + > + Copyright (c) 2024, 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 ru= n on > + enabled APs of the system. See typ= e > + EFI_AP_PROCEDURE. > + @param[in] SingleThread If TRUE, then all the enabled APs = execute > + the function specified by Procedur= e one by > + one, in ascending order of process= or handle > + number. If FALSE, then all the en= abled APs > + execute the function specified by = Procedure > + simultaneously. > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until all= APs finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on all the= enabled > + APs, and go on executing immediate= ly. If > + all return from Procedure, or Time= outInMicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + APs to return from Procedure, eith= er for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + all APs return from Procedure, the= n Procedure > + on the failed APs is terminated. A= ll enabled > + APs are available for next functio= n assigned > + by MpInitLibStartupAllAPs() or > + MPInitLibStartupThisAP(). > + If the timeout expires in blocking= mode, > + BSP returns EFI_TIMEOUT. If the t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e > for > + all APs. > + @param[out] FailedCpuList If NULL, this parameter is ignored= . > Otherwise, > + if all APs finish successfully, th= en its > + content is set to NULL. If not all= APs > + finish before timeout expires, the= n its > + content is set to address of the b= uffer > + holding handle numbers of the fail= ed APs. > + The buffer is allocated by MP Init= ialization > + library, and it's the caller's res= ponsibility to > + free the buffer with FreePool() se= rvice. > + In blocking mode, it is ready for = consumption > + when the call returns. In non-bloc= king mode, > + it is ready when WaitEvent is sign= aled. The > + list of failed CPU is terminated b= y > + END_OF_CPU_LIST. > + > + @retval EFI_SUCCESS In blocking mode, all APs have finishe= d before > + the timeout expired. > + @retval EFI_SUCCESS In non-blocking mode, function has bee= n > dispatched > + to all enabled APs. > + @retval EFI_UNSUPPORTED A non-blocking mode request was made > after the > + UEFI event EFI_EVENT_GROUP_READY_TO_BO= OT 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 initializ= ed. > + @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 ru= n on the > + designated AP of the system. See t= ype > + EFI_AP_PROCEDURE. > + @param[in] ProcessorNumber The handle number of the AP. The r= ange > is > + from 0 to the total number of logi= cal > + processors minus 1. The total numb= er of > + logical processors can be retrieve= d by > + MpInitLibGetNumberOfProcessors(). > + @param[in] WaitEvent The event created by the caller wi= th > CreateEvent() > + service. If it is NULL, then exec= ute in > + blocking mode. BSP waits until thi= s AP finish > + or TimeoutInMicroSeconds expires. = If it's > + not NULL, then execute in non-bloc= king mode. > + BSP requests the function specifie= d by > + Procedure to be started on this AP= , > + and go on executing immediately. I= f this AP > + return from Procedure or TimeoutIn= MicroSeconds > + expires, this event is signaled. T= he BSP > + can use the CheckEvent() or WaitFo= rEvent() > + services to check the state of eve= nt. Type > + EFI_EVENT is defined in CreateEven= t() in > + the Unified Extensible Firmware In= terface > + Specification. > + @param[in] TimeoutInMicroseconds Indicates the time limit in > microseconds for > + this AP to finish this Procedure, = either for > + blocking or non-blocking mode. Zer= o means > + infinity. If the timeout expires = before > + this AP returns from Procedure, th= en 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 t= imeout > + expires in non-blocking mode, Wait= Event > + is signaled with SignalEvent(). > + @param[in] ProcedureArgument The parameter passed into Procedur= e > on the > + specified AP. > + @param[out] Finished If NULL, this parameter is ignored= . In > + blocking mode, this parameter is i= gnored. > + In non-blocking mode, if AP return= s from > + Procedure before the timeout expir= es, 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 finishe= d 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_BO= OT 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 initializ= ed. > + @retval EFI_NOT_FOUND The processor with the handle specifie= d 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 p= erformed > + 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 num= ber of > + logical processors minus 1. The total num= ber 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 disable= d. > + > + @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 specifie= d 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 initializ= ed. > + > +**/ > +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 o= f > + logical processors minus 1. The total num= ber 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 sp= ecifies > + the new health status of the AP. This fla= g > + 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 pa= rameter > + is ignored. > + > + @retval EFI_SUCCESS The specified AP was enabled or disabl= ed > 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 initializ= ed. > + > +**/ > +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 738013ec0c..0f0bce0029 100644 > --- a/UefiCpuPkg/UefiCpuPkg.dsc > +++ b/UefiCpuPkg/UefiCpuPkg.dsc > @@ -213,6 +213,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 >=20 >=20 >=20 >=20 >=20 -=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 (#113696): https://edk2.groups.io/g/devel/message/113696 Mute This Topic: https://groups.io/mt/103679458/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-