From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from EUR05-AM6-obe.outbound.protection.outlook.com (EUR05-AM6-obe.outbound.protection.outlook.com [40.107.22.49]) by mx.groups.io with SMTP id smtpd.web09.5740.1635936877438361445 for ; Wed, 03 Nov 2021 03:54:38 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@armh.onmicrosoft.com header.s=selector2-armh-onmicrosoft-com header.b=ui+8s8zK; spf=pass (domain: arm.com, ip: 40.107.22.49, mailfrom: sami.mujawar@arm.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=JopFijKQhXGDgIwagoeYUArhN/M/496LPzIZ8WDOb0k=; b=ui+8s8zKUu55sphc629D+zjsNPfnvHYs7MVb3yPg8W/xj2KsMF/bs99PwBp+/3966IqlkSSxl5asRWL2Gvp5WT+SinmQbWm90Xj8DeYFqLJFagBYptUnlLaLlMC3NwFAUsePw42f6zFgYioFNWEvbU+zZ2e55E/L563YFl94m/w= Received: from AM6P193CA0069.EURP193.PROD.OUTLOOK.COM (2603:10a6:209:8e::46) by AM4PR0802MB2260.eurprd08.prod.outlook.com (2603:10a6:200:5f::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.10; Wed, 3 Nov 2021 10:54:34 +0000 Received: from AM5EUR03FT033.eop-EUR03.prod.protection.outlook.com (2603:10a6:209:8e:cafe::3d) by AM6P193CA0069.outlook.office365.com (2603:10a6:209:8e::46) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.15 via Frontend Transport; Wed, 3 Nov 2021 10:54:34 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by AM5EUR03FT033.mail.protection.outlook.com (10.152.16.99) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.14 via Frontend Transport; Wed, 3 Nov 2021 10:54:33 +0000 Received: ("Tessian outbound 4ce13939bd4a:v108"); Wed, 03 Nov 2021 10:54:32 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: a89b726424979cc8 X-CR-MTA-TID: 64aa7808 Received: from b961f45868ae.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id A07D4FE9-A901-4998-8A7C-74D44B972A87.1; Wed, 03 Nov 2021 10:54:25 +0000 Received: from EUR02-HE1-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id b961f45868ae.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Wed, 03 Nov 2021 10:54:25 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FkdHy4FTa2gpMXg+7Qd4xFVrNCqIw+hGbgIbDQiricvfjDn5ar/UJJtJ1R2HWvJaknotOB34GSsrirGE1KffAByK3r+qxto/5jGZiscb12NlK9PyTVXDmetpvuugVb0JOLZW9/+5GK8B179zS1ZfqPUvy7MPyG/i64PGpQCHY17wAug0WJnHK//FhzAARBtNUrs3C1We1+G6cZViJn/la3vw2IO7Uw08JKmyYqA1OKo9w4ik3pSGEC9pG+fjLvFWmwsMkVaduS/xocjXZEQGBfeGRPJJm1H2VNUODqaUN0srlJsYqT87bFP2iqwImkYX79XwilGKsJB+gScWbd0PVA== 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=JopFijKQhXGDgIwagoeYUArhN/M/496LPzIZ8WDOb0k=; b=QRzNf/zv95t7Q1MGSeuelqIvWLkZze227mBtH+XewBuyYh0eNrQRaoRK+5aSQo6J0S/LxGRJM1ZgMioyfNkTShKxKffegyg7Gj5ORPTYAc1xm3hVM2T8FokZoO9pSnui189n0ff2g/Ri9eKeFUjIcCOYE7idtmkg2cEMsjviBgMP1wGm+Kt5N/KIJit/sbM1STSfF/Y7Go42YDvNXSZ153Kj20vwXG3v01qEADwpsLEb41osL/eHVzMXbS1olQgHNWR4SJZDTEvDBJCZI/2xwRQqEIDPy57u5kpKZBpSxIuBTEyxmg8L6Kw39yqteh3xcNrXAJG9umzmSYp5J9j7pw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=JopFijKQhXGDgIwagoeYUArhN/M/496LPzIZ8WDOb0k=; b=ui+8s8zKUu55sphc629D+zjsNPfnvHYs7MVb3yPg8W/xj2KsMF/bs99PwBp+/3966IqlkSSxl5asRWL2Gvp5WT+SinmQbWm90Xj8DeYFqLJFagBYptUnlLaLlMC3NwFAUsePw42f6zFgYioFNWEvbU+zZ2e55E/L563YFl94m/w= Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) by AM6PR08MB3093.eurprd08.prod.outlook.com (2603:10a6:209:41::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4649.17; Wed, 3 Nov 2021 10:54:23 +0000 Received: from AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65]) by AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::54b5:239d:9896:ee65%4]) with mapi id 15.20.4669.010; Wed, 3 Nov 2021 10:54:23 +0000 Subject: Re: [edk2-devel] [PATCH v2 1/1] MdeModulePkg: Add MpServicesTest application to exercise MP Services To: devel@edk2.groups.io, rebecca@nuviainc.com, Jian J Wang , Liming Gao , nd References: <20210920154732.10181-1-rebecca@nuviainc.com> <20210920154732.10181-2-rebecca@nuviainc.com> From: "Sami Mujawar" Message-ID: <2c02b1f0-377f-4c4f-5b9b-cfd80f6a9058@arm.com> Date: Wed, 3 Nov 2021 10:54:25 +0000 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.0.1 In-Reply-To: <20210920154732.10181-2-rebecca@nuviainc.com> X-ClientProxiedBy: LO4P123CA0443.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:1a9::16) To AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) MIME-Version: 1.0 Received: from [10.1.196.43] (217.140.106.52) by LO4P123CA0443.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:1a9::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4669.10 via Frontend Transport; Wed, 3 Nov 2021 10:54:22 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 64d889ce-efa6-4c2d-e299-08d99eb851fd X-MS-TrafficTypeDiagnostic: AM6PR08MB3093:|AM4PR0802MB2260: X-Microsoft-Antispam-PRVS: x-checkrecipientrouted: true NoDisclaimer: true X-MS-Oob-TLC-OOBClassifiers: OLM:2201;OLM:4125; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: 2XmVXZ51a4oGpbEOu5O6+zDWd6/QeVxLqBU03fbiaUTt0x2FTrq30XZk0U73y9mLJPDBunRMkYTWm+N7MbwLXwQXIAN/VED7FSJHTi7J6bFliWeNDA4cXB8bRjSC7DpMLCEbbHmUtVH+i/exlAjx3c2BEK5rxBJjGLn5Mbws16xlRPsMvbcKhzzvZnvxZHjLM+GJlLfkqjJ6iDlz8zKJiFLy5J7K0WP7Ga9k4g6JkhOfgMhPl0v/HAgFAj9AF3vhx7jNmRC3LdFiow8AzthJz9+p0Ncl3JjfEwcdbUyv7WkRERvVrztX38zclcTir3+WyYn3UqS6TN+AndQDMVfSwK3HLA3ICUjqM8psjieABRY+a1HEsCdhBJQ+SDlpyddLtEiFKYlqWuWQwtiV3Ls0QNpKPKan/sqA1j+Hj/vmolniBS9L7uKmZTBQp+32Cvs0HSZx9QmLODGtAgA8FUvoGzC53vC/vLfbYnQyHlpn1pHoQDD+5tJva4viLu47qwPvIXK929CfPpbuGu5PCJfmX6O1a945MCWnrOdkBDIXCUrbquPuedfl3zDXnAhR06D2htOolbbI0OAsPSGUQVWb2EUybUE19eZNmKnyKhPe41nf791PUGCbBAbyAoLnJE1lmVOibSEtnSBOljyO+dqEu/VAgwZ6YDGd4YfBLl+W7+xoziGPQpjnp/ZgWlCp/oMG0K5tCUrMmtC19pnzL/LNPh/Gy3LO3BAaSu3VxWeUWShTxVvfvebDhV39ELnyar6Q/IU03o9KHTtD0bN2jn/GfA== X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AS8PR08MB6806.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(6029001)(4636009)(366004)(508600001)(31696002)(86362001)(2906002)(26005)(19627235002)(186003)(31686004)(44832011)(110136005)(5660300002)(38100700002)(38350700002)(316002)(33964004)(66556008)(53546011)(8936002)(66946007)(36756003)(956004)(52116002)(6636002)(30864003)(2616005)(83380400001)(6486002)(8676002)(66476007)(16576012)(43740500002)(45980500001);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM6PR08MB3093 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Return-Path: Sami.Mujawar@arm.com X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AM5EUR03FT033.eop-EUR03.prod.protection.outlook.com X-MS-Office365-Filtering-Correlation-Id-Prvs: acbbc346-cd56-4224-a2cd-08d99eb84ba1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 6GY+zYHUDe2BfpXtvlxaAJKRwWOnBmB938kkPFzmdThYPCVe1IeOVJ+gke9z24WygH0Z30Qkc6xKnChxJRMwONx7OLH1Js3nazW4eEse+qvfs6xEeoCv31MJsbuuupzw2Fz40h5a1LRnC69wYnQxBog1nFLXBq6dJZCvMJ7Gor7tn3TUOMvDH2pR8aH3zVhJLc+uBTCzKXY1kRYrCiIn4gEtYOMlHP6+dA/iM55XaGbJaEECOIih0aX5OSjPQNUBPMzJ5OycLQxujaa8W8hehadMPggf0BdAviBZ80bEVEDz7CO5l1MwipqDzoVovDtMhNVgN0jCWV7o35yrmZ8334Rlpa+s/ToLk3AmIsgKiYv8T7jxOq38VS/aYy8Lqnmy8xE7bjmm0NDB0cCZo4wL6qyh+pKu7cX52OMtk8R+y3lvZTZHvY7elYTDtjyPaeRl2NNe7a4WxwlLYJM4w1SFRG2xXVMhx4CXhiSeY7KVPGAYxTIGb94c3pcbqDhGlX4bZYCna3hO6rY2zWgqQBXyprqm16maGPgRUX0XJFphhqWXfKwC8JU1T1WScpPZkwXucbkqiosJuPFu8VAcq6BZM3GOymA6ftyZLTMIbqjMZOfxWHL+QYDvrQA7r0oljQ4s3OQfrlgVlawYtKG8v5tc3l58lnmWeR/+WTEJTX848DK5Q39LMyB4FH8Q0yyrh7Rq2ctR+KGrJGei0HLNYfdhNVilJNdOjRVjEh9Jr5EIAsg= X-Forefront-Antispam-Report: CIP:63.35.35.123;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:64aa7808-outbound-1.mta.getcheckrecipient.com;PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com;CAT:NONE;SFS:(6029001)(4636009)(36840700001)(46966006)(508600001)(44832011)(186003)(5660300002)(19627235002)(86362001)(16576012)(82310400003)(31686004)(316002)(6636002)(53546011)(8676002)(81166007)(356005)(110136005)(26005)(70586007)(2616005)(31696002)(83380400001)(30864003)(36756003)(33964004)(956004)(2906002)(6486002)(70206006)(36860700001)(8936002)(47076005)(336012)(43740500002);DIR:OUT;SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 03 Nov 2021 10:54:33.5570 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 64d889ce-efa6-4c2d-e299-08d99eb851fd X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: AM5EUR03FT033.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM4PR0802MB2260 Content-Type: multipart/alternative; boundary="------------8C048C6F73136FCF9620C2CD" Content-Language: en-GB --------------8C048C6F73136FCF9620C2CD Content-Type: text/plain; charset="utf-8"; format=flowed Content-Transfer-Encoding: quoted-printable Hi Rebecca, Apologies, I missed reviewing this patch. Please find my feedback inline marked [SAMI]. Regards, Sami Mujawar On 20/09/2021 04:47 PM, Rebecca Cran via groups.io wrote: Add a new MpServicesTest application under MdeModulePkg/Application that exercises the EFI_MP_SERVICES_PROTOCOL. Signed-off-by: Rebecca Cran --- MdeModulePkg/Application/MpServicesTest/MpServicesTest.c | 433 +++++++++= +++++++++++ MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf | 38 ++ MdeModulePkg/MdeModulePkg.dsc | 2 + 3 files changed, 473 insertions(+) diff --git a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c b/Mde= ModulePkg/Application/MpServicesTest/MpServicesTest.c new file mode 100644 index 000000000000..4eb06e6b7cbd --- /dev/null +++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c @@ -0,0 +1,433 @@ +/** @file + + Copyright (c) 2021, NUVIA Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RANDOM_PROCESSOR_RETRIES 10 + +#define AP_STARTUP_TEST_TIMEOUT_US 50000 +#define INFINITE_TIMEOUT 0 + +#define RETURN_IF_EFI_ERROR(x) \ + if (EFI_ERROR (x)) { \ + Print (L"failed: %r\n", x); \ + return; \ + } \ + else { \ + Print (L"done.\n"); \ + } + +/** The procedure to run with the MP Services interface. + + @param Buffer The procedure argument. + +**/ +STATIC +VOID +EFIAPI +ApFunction ( + IN OUT VOID *Buffer + ) +{ +} + +/** Displays information returned from MP Services Protocol. + + @param Mp The MP Services Protocol + + @return The number of CPUs in the system. + +**/ +STATIC +UINTN +PrintProcessorInformation ( + IN EFI_MP_SERVICES_PROTOCOL *Mp + ) +{ + EFI_STATUS Status; + EFI_PROCESSOR_INFORMATION CpuInfo; + UINTN Index; + UINTN NumCpu; + UINTN NumEnabledCpu; + + Status =3D Mp->GetNumberOfProcessors (Mp, &NumCpu, &NumEnabledCpu); + if (EFI_ERROR (Status)) { + Print (L"GetNumberOfProcessors failed: %r\n", Status); + } else { + Print (L"Number of CPUs: %ld, Enabled: %d\n", NumCpu, NumEnabledCpu); + } + + for (Index =3D 0; Index < NumCpu; Index++) { + Status =3D Mp->GetProcessorInfo (Mp, CPU_V2_EXTENDED_TOPOLOGY | Index,= &CpuInfo); + if (EFI_ERROR (Status)) { + Print (L"GetProcessorInfo for Processor %d failed: %r\n", Index, Sta= tus); + } else { + Print ( + L"Processor %d:\n" + L"\tID: %016lx\n" + L"\tStatus: %s | ", + Index, + CpuInfo.ProcessorId, + (CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT) ? L"BSP" : L"AP" + ); + + Print (L"%s | ", (CpuInfo.StatusFlag & PROCESSOR_ENABLED_BIT) ? L"En= abled" : L"Disabled"); + Print (L"%s\n", (CpuInfo.StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) ?= L"Healthy" : L"Faulted"); + + Print ( + L"\tLocation: Package %d, Core %d, Thread %d\n" + L"\tExtended Information: Package %d, Module %d, Tile %d, Die %d, = Core %d, Thread %d\n\n", + CpuInfo.Location.Package, + CpuInfo.Location.Core, + CpuInfo.Location.Thread, + CpuInfo.ExtendedInformation.Location2.Package, + CpuInfo.ExtendedInformation.Location2.Module, + CpuInfo.ExtendedInformation.Location2.Tile, + CpuInfo.ExtendedInformation.Location2.Die, + CpuInfo.ExtendedInformation.Location2.Core, + CpuInfo.ExtendedInformation.Location2.Thread + ); + } + } + + return NumCpu; +} + +/** Returns the index of an enabled AP selected at random. + + @param Mp The MP Services Protocol. + @param ProcessorIndex The index of a random enabled AP. + + @retval EFI_SUCCESS An enabled processor was found and returned. + @retval EFI_NOT_FOUND A processor was unable to be selected. + +**/ +STATIC +EFI_STATUS +GetRandomEnabledProcessorIndex ( + IN EFI_MP_SERVICES_PROTOCOL *Mp, + OUT UINTN *ProcessorIndex + ) +{ + UINTN Index; + UINTN IndexOfEnabledCpu; + UINTN NumCpus; + UINTN NumEnabledCpus; + UINTN IndexOfEnabledCpuToUse; + UINT16 RandomNumber; + BOOLEAN Success; + EFI_STATUS Status; + EFI_PROCESSOR_INFORMATION CpuInfo; + + IndexOfEnabledCpu =3D 0; + + Success =3D GetRandomNumber16 (&RandomNumber); + ASSERT (Success =3D=3D TRUE); + + Status =3D Mp->GetNumberOfProcessors (Mp, &NumCpus, &NumEnabledCpus); + ASSERT_EFI_ERROR (Status); + + if (NumEnabledCpus =3D=3D 1) { + Print (L"All APs are disabled\n"); + return EFI_NOT_FOUND; + } + + IndexOfEnabledCpuToUse =3D RandomNumber % NumEnabledCpus; + + for (Index =3D 0; Index < NumCpus; Index++) { + Status =3D Mp->GetProcessorInfo (Mp, Index, &CpuInfo); + ASSERT_EFI_ERROR (Status); + if ((CpuInfo.StatusFlag & PROCESSOR_ENABLED_BIT) && + !(CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT)) { + if (IndexOfEnabledCpuToUse =3D=3D IndexOfEnabledCpu) { + *ProcessorIndex =3D Index; + Status =3D EFI_SUCCESS; + break; [SAMI] Minor. I think it should be possible to return from here. In that ca= se the check below if (Index =3D=3D NumCpus) is not needed and EFI_NOT_FOUN= D can be returned at the end of the function. + } + + IndexOfEnabledCpu++; + } + } + + if (Index =3D=3D NumCpus) { + Status =3D EFI_NOT_FOUND; + } + + return Status; +} + +/** Tests for the StartupThisAP function. + + @param Mp The MP Services Protocol. + +**/ +STATIC +VOID +StartupThisApTests ( + IN EFI_MP_SERVICES_PROTOCOL *Mp + ) +{ + EFI_STATUS Status; + UINTN ProcessorIndex; + UINT32 Retries; + + Retries =3D 0; + + do { + Status =3D GetRandomEnabledProcessorIndex (Mp, &ProcessorIndex); + } while (EFI_ERROR (Status) && Retries++ < MAX_RANDOM_PROCESSOR_RETRIES)= ; + + if (EFI_ERROR (Status)) { + return; + } + + Print ( + L"StartupThisAP on Processor %d with 0 (infinite) timeout...", + ProcessorIndex + ); + + Status =3D Mp->StartupThisAP ( + Mp, + ApFunction, + ProcessorIndex, + NULL, + INFINITE_TIMEOUT, + NULL, + NULL + ); [SAMI] Please align the above code. + + RETURN_IF_EFI_ERROR (Status); [SAMI] I can see that the RETURN_IF_EFI_ERROR() macro is avoiding repetitiv= e code. But I am concerned that the return statement in the macro is hiding= the program flow. + + Retries =3D 0; + + do { + Status =3D GetRandomEnabledProcessorIndex (Mp, &ProcessorIndex); + } while (EFI_ERROR (Status) && Retries++ < MAX_RANDOM_PROCESSOR_RETRIES)= ; + + if (EFI_ERROR (Status)) { + return; + } + + Print ( + L"StartupThisAP on Processor %d with %dms timeout...", + ProcessorIndex, + AP_STARTUP_TEST_TIMEOUT_US / 1000 + ); + Status =3D Mp->StartupThisAP ( + Mp, + ApFunction, + ProcessorIndex, + NULL, + AP_STARTUP_TEST_TIMEOUT_US, + NULL, + NULL + ); + RETURN_IF_EFI_ERROR (Status); +} + +/** Tests for the StartupAllAPs function. + + @param Mp The MP Services Protocol. + @param NumCpus The number of CPUs in the system. + +**/ +STATIC +VOID +StartupAllAPsTests ( + IN EFI_MP_SERVICES_PROTOCOL *Mp, + IN UINTN NumCpus + ) +{ + EFI_STATUS Status; + UINTN Timeout; + + Print (L"Running with SingleThread FALSE, 0 (infinite) timeout..."); + Status =3D Mp->StartupAllAPs (Mp, ApFunction, FALSE, NULL, INFINITE_TIME= OUT, NULL, NULL); + RETURN_IF_EFI_ERROR (Status); + + Timeout =3D NumCpus * AP_STARTUP_TEST_TIMEOUT_US; + + Print (L"Running with SingleThread TRUE, %dms timeout...", Timeout / 100= 0); + Status =3D Mp->StartupAllAPs ( + Mp, + ApFunction, + TRUE, + NULL, + Timeout, + NULL, + NULL + ); + RETURN_IF_EFI_ERROR (Status); +} + +/** Tests for the EnableDisableAP function. + + @param Mp The MP Services Protocol. + @param NumCpus The number of CPUs in the system. + +**/ +STATIC +VOID +EnableDisableAPTests ( + IN EFI_MP_SERVICES_PROTOCOL *Mp, + IN UINTN NumCpus + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT32 HealthFlag; + + HealthFlag =3D 0; + + for (Index =3D 1; Index < NumCpus; Index++) { + Print (L"Disabling Processor %d with HealthFlag faulted...", Index); + Status =3D Mp->EnableDisableAP (Mp, Index, FALSE, &HealthFlag); + RETURN_IF_EFI_ERROR (Status); + } + + HealthFlag =3D PROCESSOR_HEALTH_STATUS_BIT; + + for (Index =3D 1; Index < NumCpus; Index++) { + Print (L"Enabling Processor %d with HealthFlag healthy...", Index); + Status =3D Mp->EnableDisableAP (Mp, Index, TRUE, &HealthFlag); + RETURN_IF_EFI_ERROR (Status); + } +} + +/** Tests for the SwitchBSP function. + + @param Mp The MP Services Protocol. + @param NumCpus The number of CPUs in the system. + +**/ +STATIC +VOID +SwitchBSPTests ( + IN EFI_MP_SERVICES_PROTOCOL *Mp, + IN UINTN NumCpus + ) +{ + EFI_STATUS Status; + UINTN Index; + + for (Index =3D 1; Index < NumCpus; Index++) { + Print (L"Switching BSP to Processor %d with EnableOldBSP FALSE...", In= dex); + Status =3D Mp->SwitchBSP (Mp, Index, FALSE); [SAMI] The SwitchBsp call can only be performed by the current BSP. So, I a= m not sure if this would work in a for loop. + RETURN_IF_EFI_ERROR (Status); + } + + for (Index =3D 0; Index < NumCpus; Index++) { + Print (L"Switching BSP to Processor %d with EnableOldBSP TRUE...", Ind= ex); + Status =3D Mp->SwitchBSP (Mp, Index, TRUE); + RETURN_IF_EFI_ERROR (Status); + } +} + +/** + The user Entry Point for Application. The user code starts with this fun= ction + as the real entry point for the application. + + @param[in] ImageHandle The firmware allocated handle for the EFI imag= e. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry po= int. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *Mp; + EFI_HANDLE *pHandle; + UINTN HandleCount; + UINTN BspId; + UINTN NumCpus; + UINTN Index; + + pHandle =3D NULL; + HandleCount =3D 0; + BspId =3D 0; + + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiMpServiceProtocolGuid, + NULL, + &HandleCount, + &pHandle + ); + + if (EFI_ERROR (Status)) { + Print (L"Failed to locate EFI_MP_SERVICES_PROTOCOL (%r). Not installed= on platform?\n", Status); + return EFI_NOT_FOUND; + } + + for (Index =3D 0; Index < HandleCount; Index++) { + Status =3D gBS->OpenProtocol ( + *pHandle, + &gEfiMpServiceProtocolGuid, + (VOID **)&Mp, + NULL, + gImageHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + pHandle++; + } + + Print (L"Exercising WhoAmI\n\n"); + Status =3D Mp->WhoAmI (Mp, &BspId); + if (EFI_ERROR (Status)) { + Print (L"WhoAmI failed: %r\n", Status); + return Status; + } else { + Print (L"WhoAmI: %016lx\n", BspId); + } + + Print (L"\n"); + Print ( + L"Exercising GetNumberOfProcessors and GetProcessorInformation with " + L"CPU_V2_EXTENDED_TOPOLOGY\n\n" + ); + NumCpus =3D PrintProcessorInformation (Mp); + if (NumCpus < 2) { + Print (L"UP system found. Not running further tests.\n"); + return EFI_INVALID_PARAMETER; + } + + Print (L"\n"); + Print (L"Exercising StartupThisAP:\n\n"); + StartupThisApTests (Mp); + + Print (L"\n"); + Print (L"Exercising StartupAllAPs:\n\n"); + StartupAllAPsTests (Mp, NumCpus); + + Print (L"\n"); + Print (L"Exercising EnableDisableAP:\n\n"); + EnableDisableAPTests (Mp, NumCpus); + + Print (L"\n"); + Print (L"Exercising SwitchBSP\n\n"); + SwitchBSPTests (Mp, NumCpus); + + gBS->CloseProtocol (pHandle, &gEfiMpServiceProtocolGuid, gImageHandle, N= ULL); + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf b/M= deModulePkg/Application/MpServicesTest/MpServicesTest.inf new file mode 100644 index 000000000000..8a21ca70d8fa --- /dev/null +++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf @@ -0,0 +1,38 @@ +## @file +# UEFI Application to exercise EFI_MP_SERVICES_PROTOCOL. +# +# Copyright (c) 2021, NUVIA Inc. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 1.29 + BASE_NAME =3D MpServicesTest + FILE_GUID =3D 43e9defa-7209-4b0d-b136-cc4ca02cb469 + MODULE_TYPE =3D UEFI_APPLICATION + VERSION_STRING =3D 0.1 + ENTRY_POINT =3D UefiMain + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 AARCH64 +# + +[Sources] + MpServicesTest.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + RngLib + UefiApplicationEntryPoint + UefiLib + +[Protocols] + gEfiMpServiceProtocolGuid ## CONSUMES + diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index b1d83461865e..1cf5ccd30d40 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -164,6 +164,7 @@ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll= ocationLib.inf DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + RngLib|MdePkg/Library/DxeRngLib/DxeRngLib.inf [LibraryClasses.common.MM_STANDALONE] HobLib|MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf @@ -215,6 +216,7 @@ MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf + MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf MdeModulePkg/Logo/Logo.inf IMPORTANT NOTICE: The contents of this email and any attachments are confid= ential and may also be privileged. If you are not the intended recipient, p= lease notify the sender immediately and do not disclose the contents to any= other person, use it for any purpose, or store or copy the information in = any medium. Thank you. --------------8C048C6F73136FCF9620C2CD Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable

Hi Rebecca,

Apologies, I missed reviewing this patch.

Please find my feedback inline marked [SAMI].

Regards,

Sami Mujawar


On 20/09/2021 04:47 PM, Rebecca Cran via gro= ups.io wrote:
Add a new MpServicesTest application under MdeModulePkg/Appl=
ication that
exercises the EFI_MP_SERVICES_PROTOCOL.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
 MdeModulePkg/Application/MpServicesTest/MpServicesTest.c   | 433 +++++++++=
+++++++++++
 MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf |  38 ++
 MdeModulePkg/MdeModulePkg.dsc                              |   2 +
 3 files changed, 473 insertions(+)

diff --git a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c b/Mde=
ModulePkg/Application/MpServicesTest/MpServicesTest.c
new file mode 100644
index 000000000000..4eb06e6b7cbd
--- /dev/null
+++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.c
@@ -0,0 +1,433 @@
+/** @file
+
+    Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+    SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/DebugLib.h>
+#include <Library/RngLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Pi/PiMultiPhase.h>
+#include <Protocol/MpService.h>
+
+#define MAX_RANDOM_PROCESSOR_RETRIES 10
+
+#define AP_STARTUP_TEST_TIMEOUT_US  50000
+#define INFINITE_TIMEOUT            0
+
+#define RETURN_IF_EFI_ERROR(x)   \
+  if (EFI_ERROR (x)) {           \
+    Print (L"failed: %r\n", x);  \
+    return;                      \
+  }                              \
+  else {                         \
+    Print (L"done.\n");          \
+  }
+
+/** The procedure to run with the MP Services interface.
+
+  @param Buffer The procedure argument.
+
+**/
+STATIC
+VOID
+EFIAPI
+ApFunction (
+  IN OUT VOID *Buffer
+  )
+{
+}
+
+/** Displays information returned from MP Services Protocol.
+
+  @param Mp  The MP Services Protocol
+
+  @return The number of CPUs in the system.
+
+**/
+STATIC
+UINTN
+PrintProcessorInformation (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_PROCESSOR_INFORMATION  CpuInfo;
+  UINTN                      Index;
+  UINTN                      NumCpu;
+  UINTN                      NumEnabledCpu;
+
+  Status =3D Mp->GetNumberOfProcessors (Mp, &NumCpu, &NumEnable=
dCpu);
+  if (EFI_ERROR (Status)) {
+    Print (L"GetNumberOfProcessors failed: %r\n", Status);
+  } else {
+    Print (L"Number of CPUs: %ld, Enabled: %d\n", NumCpu, NumEna=
bledCpu);
+  }
+
+  for (Index =3D 0; Index < NumCpu; Index++) {
+    Status =3D Mp->GetProcessorInfo (Mp, CPU_V2_EXTENDED_TOPOLOGY | Ind=
ex, &CpuInfo);
+    if (EFI_ERROR (Status)) {
+      Print (L"GetProcessorInfo for Processor %d failed: %r\n", =
Index, Status);
+    } else {
+      Print (
+        L"Processor %d:\n"
+        L"\tID: %016lx\n"
+        L"\tStatus: %s | ",
+        Index,
+        CpuInfo.ProcessorId,
+        (CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT) ? L"BSP"=
 : L"AP"
+        );
+
+      Print (L"%s | ", (CpuInfo.StatusFlag & PROCESSOR_ENABL=
ED_BIT) ? L"Enabled" : L"Disabled");
+      Print (L"%s\n", (CpuInfo.StatusFlag & PROCESSOR_HEALTH=
_STATUS_BIT) ? L"Healthy" : L"Faulted");
+
+      Print (
+        L"\tLocation: Package %d, Core %d, Thread %d\n"
+        L"\tExtended Information: Package %d, Module %d, Tile %d, Die=
 %d, Core %d, Thread %d\n\n",
+        CpuInfo.Location.Package,
+        CpuInfo.Location.Core,
+        CpuInfo.Location.Thread,
+        CpuInfo.ExtendedInformation.Location2.Package,
+        CpuInfo.ExtendedInformation.Location2.Module,
+        CpuInfo.ExtendedInformation.Location2.Tile,
+        CpuInfo.ExtendedInformation.Location2.Die,
+        CpuInfo.ExtendedInformation.Location2.Core,
+        CpuInfo.ExtendedInformation.Location2.Thread
+        );
+    }
+  }
+
+  return NumCpu;
+}
+
+/** Returns the index of an enabled AP selected at random.
+
+  @param Mp             The MP Services Protocol.
+  @param ProcessorIndex The index of a random enabled AP.
+
+  @retval EFI_SUCCESS   An enabled processor was found and returned.
+  @retval EFI_NOT_FOUND A processor was unable to be selected.
+
+**/
+STATIC
+EFI_STATUS
+GetRandomEnabledProcessorIndex (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp,
+  OUT UINTN *ProcessorIndex
+  )
+{
+  UINTN                      Index;
+  UINTN                      IndexOfEnabledCpu;
+  UINTN                      NumCpus;
+  UINTN                      NumEnabledCpus;
+  UINTN                      IndexOfEnabledCpuToUse;
+  UINT16                     RandomNumber;
+  BOOLEAN                    Success;
+  EFI_STATUS                 Status;
+  EFI_PROCESSOR_INFORMATION  CpuInfo;
+
+  IndexOfEnabledCpu =3D 0;
+
+  Success =3D GetRandomNumber16 (&RandomNumber);
+  ASSERT (Success =3D=3D TRUE);
+
+  Status =3D Mp->GetNumberOfProcessors (Mp, &NumCpus, &NumEnabl=
edCpus);
+  ASSERT_EFI_ERROR (Status);
+
+  if (NumEnabledCpus =3D=3D 1) {
+    Print (L"All APs are disabled\n");
+    return EFI_NOT_FOUND;
+  }
+
+  IndexOfEnabledCpuToUse =3D RandomNumber % NumEnabledCpus;
+
+  for (Index =3D 0; Index < NumCpus; Index++) {
+    Status =3D Mp->GetProcessorInfo (Mp, Index, &CpuInfo);
+    ASSERT_EFI_ERROR (Status);
+    if ((CpuInfo.StatusFlag & PROCESSOR_ENABLED_BIT) &&
+        !(CpuInfo.StatusFlag & PROCESSOR_AS_BSP_BIT)) {
+      if (IndexOfEnabledCpuToUse =3D=3D IndexOfEnabledCpu) {
+        *ProcessorIndex =3D Index;
+        Status =3D EFI_SUCCESS;
+        break;
[SAMI] Minor. I think it should be possible to return from here. In that ca= se the check below if (Index =3D=3D NumCpus) is not needed and EFI_NOT_FOUN= D can be returned at the end of the function.
+      }
+
+      IndexOfEnabledCpu++;
+    }
+  }
+
+  if (Index =3D=3D NumCpus) {
+    Status =3D EFI_NOT_FOUND;
+  }
+
+  return Status;
+}
+
+/** Tests for the StartupThisAP function.
+
+  @param Mp The MP Services Protocol.
+
+**/
+STATIC
+VOID
+StartupThisApTests (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       ProcessorIndex;
+  UINT32      Retries;
+
+  Retries =3D 0;
+
+  do {
+    Status =3D GetRandomEnabledProcessorIndex (Mp, &ProcessorIndex);
+  } while (EFI_ERROR (Status) && Retries++ < MAX_RANDOM_PROCESS=
OR_RETRIES);
+
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  Print (
+    L"StartupThisAP on Processor %d with 0 (infinite) timeout..."=
;,
+    ProcessorIndex
+    );
+
+  Status =3D Mp->StartupThisAP (
+    Mp,
+    ApFunction,
+    ProcessorIndex,
+    NULL,
+    INFINITE_TIMEOUT,
+    NULL,
+    NULL
+    );
[SAMI] Please align the above code.
+
+  RETURN_IF_EFI_ERROR (Status);
[SAMI] I can see that the RETURN_IF_EFI_ERROR() macro is avoiding repetitiv= e code. But I am concerned that the return statement in the macro is hiding= the program flow.
+
+  Retries =3D 0;
+
+  do {
+    Status =3D GetRandomEnabledProcessorIndex (Mp, &ProcessorIndex);
+  } while (EFI_ERROR (Status) && Retries++ < MAX_RANDOM_PROCESS=
OR_RETRIES);
+
+  if (EFI_ERROR (Status)) {
+    return;
+  }
+
+  Print (
+    L"StartupThisAP on Processor %d with %dms timeout...",
+    ProcessorIndex,
+    AP_STARTUP_TEST_TIMEOUT_US / 1000
+    );
+  Status =3D Mp->StartupThisAP (
+                 Mp,
+                 ApFunction,
+                 ProcessorIndex,
+                 NULL,
+                 AP_STARTUP_TEST_TIMEOUT_US,
+                 NULL,
+                 NULL
+                 );
+  RETURN_IF_EFI_ERROR (Status);
+}
+
+/** Tests for the StartupAllAPs function.
+
+  @param Mp      The MP Services Protocol.
+  @param NumCpus The number of CPUs in the system.
+
+**/
+STATIC
+VOID
+StartupAllAPsTests (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp,
+  IN UINTN NumCpus
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Timeout;
+
+  Print (L"Running with SingleThread FALSE, 0 (infinite) timeout...&q=
uot;);
+  Status =3D Mp->StartupAllAPs (Mp, ApFunction, FALSE, NULL, INFINITE_T=
IMEOUT, NULL, NULL);
+  RETURN_IF_EFI_ERROR (Status);
+
+  Timeout =3D NumCpus * AP_STARTUP_TEST_TIMEOUT_US;
+
+  Print (L"Running with SingleThread TRUE, %dms timeout...", Tim=
eout / 1000);
+  Status =3D Mp->StartupAllAPs (
+                 Mp,
+                 ApFunction,
+                 TRUE,
+                 NULL,
+                 Timeout,
+                 NULL,
+                 NULL
+                 );
+  RETURN_IF_EFI_ERROR (Status);
+}
+
+/** Tests for the EnableDisableAP function.
+
+  @param Mp      The MP Services Protocol.
+  @param NumCpus The number of CPUs in the system.
+
+**/
+STATIC
+VOID
+EnableDisableAPTests (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp,
+  IN UINTN                    NumCpus
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Index;
+  UINT32      HealthFlag;
+
+  HealthFlag =3D 0;
+
+  for (Index =3D 1; Index < NumCpus; Index++) {
+    Print (L"Disabling Processor %d with HealthFlag faulted...",=
 Index);
+    Status =3D Mp->EnableDisableAP (Mp, Index, FALSE, &HealthFlag);
+    RETURN_IF_EFI_ERROR (Status);
+  }
+
+  HealthFlag =3D PROCESSOR_HEALTH_STATUS_BIT;
+
+  for (Index =3D 1; Index < NumCpus; Index++) {
+    Print (L"Enabling Processor %d with HealthFlag healthy...", =
Index);
+    Status =3D Mp->EnableDisableAP (Mp, Index, TRUE, &HealthFlag);
+    RETURN_IF_EFI_ERROR (Status);
+  }
+}
+
+/** Tests for the SwitchBSP function.
+
+  @param Mp      The MP Services Protocol.
+  @param NumCpus The number of CPUs in the system.
+
+**/
+STATIC
+VOID
+SwitchBSPTests (
+  IN EFI_MP_SERVICES_PROTOCOL *Mp,
+  IN UINTN                    NumCpus
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Index;
+
+  for (Index =3D 1; Index < NumCpus; Index++) {
+    Print (L"Switching BSP to Processor %d with EnableOldBSP FALSE...=
", Index);
+    Status =3D Mp->SwitchBSP (Mp, Index, FALSE);
[SAMI] The SwitchBsp call can only be performed by the current BSP. So, I a= m not sure if this would work in a for loop.
+    RETURN_IF_EFI_ERROR (Status);
+  }
+
+  for (Index =3D 0; Index < NumCpus; Index++) {
+    Print (L"Switching BSP to Processor %d with EnableOldBSP TRUE...&=
quot;, Index);
+    Status =3D Mp->SwitchBSP (Mp, Index, TRUE);
+    RETURN_IF_EFI_ERROR (Status);
+  }
+}
+
+/**
+  The user Entry Point for Application. The user code starts with this fun=
ction
+  as the real entry point for the application.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI imag=
e.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry po=
int.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                Status;
+  EFI_MP_SERVICES_PROTOCOL  *Mp;
+  EFI_HANDLE                *pHandle;
+  UINTN                     HandleCount;
+  UINTN                     BspId;
+  UINTN                     NumCpus;
+  UINTN                     Index;
+
+  pHandle     =3D NULL;
+  HandleCount =3D 0;
+  BspId =3D 0;
+
+  Status =3D gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiMpServiceProtocolGuid,
+                  NULL,
+                  &HandleCount,
+                  &pHandle
+                  );
+
+  if (EFI_ERROR (Status)) {
+    Print (L"Failed to locate EFI_MP_SERVICES_PROTOCOL (%r). Not inst=
alled on platform?\n", Status);
+    return EFI_NOT_FOUND;
+  }
+
+  for (Index =3D 0; Index < HandleCount; Index++) {
+    Status =3D gBS->OpenProtocol (
+                    *pHandle,
+                    &gEfiMpServiceProtocolGuid,
+                    (VOID **)&Mp,
+                    NULL,
+                    gImageHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    pHandle++;
+  }
+
+  Print (L"Exercising WhoAmI\n\n");
+  Status =3D Mp->WhoAmI (Mp, &BspId);
+  if (EFI_ERROR (Status)) {
+    Print (L"WhoAmI failed: %r\n", Status);
+    return Status;
+  } else {
+    Print (L"WhoAmI: %016lx\n", BspId);
+  }
+
+  Print (L"\n");
+  Print (
+    L"Exercising GetNumberOfProcessors and GetProcessorInformation wi=
th "
+    L"CPU_V2_EXTENDED_TOPOLOGY\n\n"
+    );
+  NumCpus =3D PrintProcessorInformation (Mp);
+  if (NumCpus < 2) {
+    Print (L"UP system found. Not running further tests.\n");
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Print (L"\n");
+  Print (L"Exercising StartupThisAP:\n\n");
+  StartupThisApTests (Mp);
+
+  Print (L"\n");
+  Print (L"Exercising StartupAllAPs:\n\n");
+  StartupAllAPsTests (Mp, NumCpus);
+
+  Print (L"\n");
+  Print (L"Exercising EnableDisableAP:\n\n");
+  EnableDisableAPTests (Mp, NumCpus);
+
+  Print (L"\n");
+  Print (L"Exercising SwitchBSP\n\n");
+  SwitchBSPTests (Mp, NumCpus);
+
+  gBS->CloseProtocol (pHandle, &gEfiMpServiceProtocolGuid, gImageHa=
ndle, NULL);
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf b/M=
deModulePkg/Application/MpServicesTest/MpServicesTest.inf
new file mode 100644
index 000000000000..8a21ca70d8fa
--- /dev/null
+++ b/MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf
@@ -0,0 +1,38 @@
+## @file
+#  UEFI Application to exercise EFI_MP_SERVICES_PROTOCOL.
+#
+#  Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    =3D 1.29
+  BASE_NAME                      =3D MpServicesTest
+  FILE_GUID                      =3D 43e9defa-7209-4b0d-b136-cc4ca02cb469
+  MODULE_TYPE                    =3D UEFI_APPLICATION
+  VERSION_STRING                 =3D 0.1
+  ENTRY_POINT                    =3D UefiMain
+
+#
+# The following information is for reference only and not required by the =
build tools.
+#
+#  VALID_ARCHITECTURES           =3D IA32 X64 AARCH64
+#
+
+[Sources]
+  MpServicesTest.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  RngLib
+  UefiApplicationEntryPoint
+  UefiLib
+
+[Protocols]
+  gEfiMpServiceProtocolGuid    ## CONSUMES
+
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index b1d83461865e..1cf5ccd30d40 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -164,6 +164,7 @@
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll=
ocationLib.inf
   DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf
   FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+  RngLib|MdePkg/Library/DxeRngLib/DxeRngLib.inf
=20
 [LibraryClasses.common.MM_STANDALONE]
   HobLib|MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
@@ -215,6 +216,7 @@
   MdeModulePkg/Application/HelloWorld/HelloWorld.inf
   MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
   MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
+  MdeModulePkg/Application/MpServicesTest/MpServicesTest.inf
=20
   MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
   MdeModulePkg/Logo/Logo.inf

IMPORTANT NOTICE: The contents of this email and any attachments are confid= ential and may also be privileged. If you are not the intended recipient, p= lease notify the sender immediately and do not disclose the contents to any= other person, use it for any purpose, or store or copy the information in any medium. Thank you. --------------8C048C6F73136FCF9620C2CD--