From nobody Tue May 21 07:31:39 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+107447+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+107447+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1690953347; cv=none; d=zohomail.com; s=zohoarc; b=H4BQl01IjCj9E7tCYqRgZ37cTWX74d3j9vFoVsONuvos0bewYztF+yINZweV2iKwnJlzFtoA2Lz4kgiAXtsGpYatwxyG22Ku/cwQd9qpAOdejvKPxxZLuGRqzxaP79IcsZ1YmfeSsTcZvhLXQ4ptIHopEDYVvqg6MnLLOfuRrzw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1690953347; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=fAKyGa+c51xSG3mUKQQprsshLPY1HdiBU1oIQlTSOp0=; b=BpNzyvs0LZb4wttKeBbPidrD0p2ODW699QyQo/uMzAP3LCVvZnhG0D2L16PV9ZFd5dg3tS/nX9XRyTTlM3Y267xxNmfu8Nmrr8k1pXvpmrRnAmklBG322gDKbudLe/RrWgXgRyD24HFB0BO23wr3DnJrmNfMjfJ4WYF2LhJJT3o= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+107447+1787277+3901457@groups.io Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1690953347004121.99242284836203; Tue, 1 Aug 2023 22:15:47 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=HTjTdPjdiCDH3/nmKOrF9dOM6RmFDafkSYHDMRsNa1E=; c=relaxed/simple; d=groups.io; h=From:To:Cc:References:In-Reply-To:Subject:Date:Message-ID:MIME-Version:Thread-Index:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Language; s=20140610; t=1690953346; v=1; b=PuVo1oYhEGFomoQ8LQVnY83O8R/4+WhhndMcA+9T65IQVnoPPIcYqRi0kJwlxoqPMFh9lXDC jXTP8GB4M27xn0soVe4wiYnXmsMwKcwsKJe7hvbXY5dY/jPwSyHQXxmptZqv+rK82n8YOgpkwMp 4vsofH34v9sBwngZN1v5lkFw= X-Received: by 127.0.0.2 with SMTP id Jhg9YY1788612xWMyEeJJcZG; Tue, 01 Aug 2023 22:15:46 -0700 X-Received: from cxsh.intel-email.com (cxsh.intel-email.com [121.46.250.151]) by mx.groups.io with SMTP id smtpd.web10.8017.1690953343155227259 for ; Tue, 01 Aug 2023 22:15:45 -0700 X-Received: from cxsh.intel-email.com (localhost [127.0.0.1]) by cxsh.intel-email.com (Postfix) with ESMTP id E9C73DDA7D3 for ; Wed, 2 Aug 2023 13:15:40 +0800 (CST) X-Received: from localhost (localhost [127.0.0.1]) by cxsh.intel-email.com (Postfix) with ESMTP id E41C3DDA7C8 for ; Wed, 2 Aug 2023 13:15:40 +0800 (CST) X-Received: from mail.byosoft.com.cn (mail.byosoft.com.cn [58.240.74.242]) by cxsh.intel-email.com (Postfix) with SMTP id B2A04DDA794 for ; Wed, 2 Aug 2023 13:15:36 +0800 (CST) X-Received: from DESKTOPS6D0PVI ([58.246.60.130]) (envelope-sender ) by 192.168.6.13 with ESMTP for ; Wed, 02 Aug 2023 13:15:34 +0800 X-WM-Sender: gaoliming@byosoft.com.cn X-Originating-IP: 58.246.60.130 X-WM-AuthFlag: YES X-WM-AuthUser: gaoliming@byosoft.com.cn From: "gaoliming via groups.io" To: , Cc: "'Jian J Wang'" , "'Dandan Bi'" , "'Debkumar De'" , "'Catharine West'" , "'Mike Turner'" References: <20230720210729.774-1-kuqin12@gmail.com> <20230720210729.774-4-kuqin12@gmail.com> <01b901d9be9e$21a964c0$64fc2e40$@byosoft.com.cn> In-Reply-To: Subject: =?UTF-8?B?5Zue5aSNOiBbZWRrMi1kZXZlbF0g5Zue5aSNOiBbUEFUQ0ggdjEgMy80XSBNZGVNb2R1bGVQa2c6IFBlaU1haW46IEludHJvZHVjZSBpbXBsZW1lbnRhdGlvbiBvZiBkZWxheWVkIGRpc3BhdGNo?= Date: Wed, 2 Aug 2023 13:15:34 +0800 Message-ID: <003c01d9c500$5dcf2a30$196d7e90$@byosoft.com.cn> MIME-Version: 1.0 Thread-Index: AQHmQqk72a+h6fM/RhcnPsN27NW3TwNcSvR8AbusGHUBstOTyq+HBSBA 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,gaoliming@byosoft.com.cn List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: 5C81IaiiCsPQxSLn28mMdBq8x1787277AA= Content-Type: multipart/alternative; boundary="----=_NextPart_000_003D_01D9C543.6BFD8DC0" Content-Language: zh-cn X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1690953348781100003 ------=_NextPart_000_003D_01D9C543.6BFD8DC0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Kun: PcdDelayedDispatchMaxEntries is not required. The required Entry number ca= n be increased at boot time. You can see MaxFvCount in PrivateData that is = increased by FV_GROWTH_STEP =20 Thanks Liming =E5=8F=91=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io = =E4=BB=A3=E8=A1=A8 Kun Qin =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4: 2023=E5=B9=B48=E6=9C=881=E6=97=A5 12:= 16 =E6=94=B6=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io; gaoliming@byosoft.com.cn =E6=8A=84=E9=80=81: 'Jian J Wang' ; 'Dandan Bi' ; 'Debkumar De' ; 'Catharine West' = ; 'Mike Turner' =E4=B8=BB=E9=A2=98: Re: [edk2-devel] =E5=9B=9E=E5=A4=8D: [PATCH v1 3/4] Mde= ModulePkg: PeiMain: Introduce implementation of delayed dispatch =20 Hi Liming, Thanks for the feedback. Per your feedback (I suggest to define MACRO in PeiCore for them. If there = is real usage model, new PCD can be introduced later.) on the following new= PCDs:=20 gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeoutUs gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxEntries Given this feature has been used internally at Project MU for a while, I collected some feedback from the consumer platforms: - Delayed dispatch is a feature that can be used for power up sequence, and thus the value of maximum entries in this case can depend on the number of = PCI devices on the platform, and thus hardcoding the value as a macro definitio= n will limit the usage and we might come to update it very soon. - There is already usage on our platforms that would override the timeout P= CDs to based on the firmware builds. For example, on a test build, we might reg= ister extra entries to the PPI and thus extend the completion timeout. I agree with your comments on other fronts. Please let me know if you have = further concerns regarding the PCDs above. I can send out an updated version after = your input on those. Thanks, Kun On 7/24/2023 7:17 PM, gaoliming via groups.io wrote: Kun:=20 I add my comments below.=20 =20 -----=E9=82=AE=E4=BB=B6=E5=8E=9F=E4=BB=B6----- =E5=8F=91=E4=BB=B6=E4=BA=BA: Kun Qin =E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4: 2023=E5=B9=B47=E6=9C=8821=E6=97=A5 5:= 07 =E6=94=B6=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io =20 =E6=8A=84=E9=80=81: Jian J Wang ; Dandan Bi ; Liming Gao ; Debkumar De ; Cathar= ine West ; Mike Turner = =E4=B8=BB=E9=A2=98: [PATCH v1 3/4] MdeModulePkg: PeiMain: Introduce impleme= ntation of delayed dispatch =20 REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4496 =20 This change adds the implementation that fits the needs and description of PI spec defined Delayed Dispatch PPI in Pei Core. =20 The PPI would allow minimal delay for registered callbacks. As well as allowing other functions to wait for GUIDed delayed dispatch callbacks. =20 Cc: Jian J Wang Cc: Dandan Bi Cc: Liming Gao Cc: Debkumar De Cc: Catharine West =20 Co-authored-by: Mike Turner Signed-off-by: Kun Qin --- MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 353 ++++++++++++++++++++ MdeModulePkg/Core/Pei/PeiMain/PeiMain.c | 3 + MdeModulePkg/Core/Pei/PeiMain.h | 76 +++++ MdeModulePkg/Core/Pei/PeiMain.inf | 7 + MdeModulePkg/MdeModulePkg.dec | 15 + 5 files changed, 454 insertions(+) =20 diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c index 5f32ebb560ae..50e59bdbe732 100644 --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c @@ -3,12 +3,339 @@ =20 =20 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
=20 (C) Copyright 2016 Hewlett Packard Enterprise Development LP
=20 +Copyright (c) Microsoft Corporation. =20 SPDX-License-Identifier: BSD-2-Clause-Patent =20 =20 =20 **/ =20 =20 =20 #include "PeiMain.h" =20 =20 =20 +/** =20 + DelayedDispatchDispatcher =20 + =20 + ayed Dispach cycle (ie one pass) through each entry, calling functions when their =20 + e has expired. When UniqueId is specified, if there are any of the specified entries =20 + the dispatch queue during dispatch, repeat the DelayedDispatch cycle. =20 + =20 [Liming] Above comments are incomplete. Please update.=20 =20 + @param DelayedDispatchTable Pointer to dispatch table =20 + @param OPTIONAL UniqueId used to insure particular time is met. =20 + =20 + @return BOOLEAN =20 +**/ =20 +BOOLEAN =20 +DelayedDispatchDispatcher ( =20 + IN DELAYED_DISPATCH_TABLE *DelayedDispatchTable, =20 + IN EFI_GUID *UniqueId OPTIONAL =20 + ); =20 + =20 +/** =20 + DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch =20 + entries are complete before exiting PEI. =20 + =20 + @param[in] PeiServices - Pointer to PEI Services Table. =20 + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that =20 + caused this function to execute. =20 + @param[in] Ppi - Pointer to the PPI data associated with this function. =20 + =20 + @retval EFI_STATUS - Always return EFI_SUCCESS =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchOnEndOfPei ( =20 + IN EFI_PEI_SERVICES **PeiServices, =20 + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, =20 + IN VOID *Ppi =20 + ); =20 + =20 +EFI_DELAYED_DISPATCH_PPI mDelayedDispatchPpi =3D { PeiDelayedDispatchRegister, PeiDelayedDispatchWaitOnUniqueId }; =20 +EFI_PEI_PPI_DESCRIPTOR mDelayedDispatchDesc =3D { =20 + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), =20 + &gEfiPeiDelayedDispatchPpiGuid, =20 + &mDelayedDispatchPpi =20 +}; =20 + =20 +EFI_PEI_NOTIFY_DESCRIPTOR mDelayedDispatchNotifyDesc =3D { =20 + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, =20 + &gEfiEndOfPeiSignalPpiGuid, =20 + PeiDelayedDispatchOnEndOfPei =20 +}; =20 + =20 +/** =20 + Helper function to look up DELAYED_DISPATCH_TABLE published in HOB. =20 + =20 + @return Pointer to DELAYED_DISPATCH_TABLE from HOB =20 +**/ =20 +DELAYED_DISPATCH_TABLE * =20 +GetDelayedDispatchTable ( =20 + VOID =20 + ) =20 +{ =20 + EFI_HOB_GUID_TYPE *GuidHob; =20 + =20 + GuidHob =3D GetFirstGuidHob (&gEfiDelayedDispatchTableGuid); =20 + if (NULL =3D=3D GuidHob) { =20 + DEBUG ((DEBUG_ERROR, "Delayed Dispatch PPI ERROR - Delayed Dispatch Hob not available.\n")); =20 + ASSERT (FALSE); =20 + return NULL; =20 + } =20 + =20 + return (DELAYED_DISPATCH_TABLE *)GET_GUID_HOB_DATA (GuidHob); =20 +} =20 + =20 +/** =20 +Register a callback to be called after a minimum delay has occurred. =20 + =20 +This service is the single member function of the EFI_DELAYED_DISPATCH_PPI =20 + =20 + @param[in] This Pointer to the EFI_DELAYED_DISPATCH_PPI instance =20 + @param[in] Function Function to call back =20 + @param[in] Context Context data =20 + @param[in] UniqueId GUID for this Delayed Dispatch request. =20 + @param[in] Delay Delay interval =20 + =20 + @retval EFI_SUCCESS Function successfully loaded =20 + @retval EFI_INVALID_PARAMETER One of the Arguments is not supported =20 + @retval EFI_OUT_OF_RESOURCES No more entries =20 + =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchRegister ( =20 + IN EFI_DELAYED_DISPATCH_PPI *This, =20 + IN EFI_DELAYED_DISPATCH_FUNCTION Function, =20 + IN UINT64 Context, =20 + IN EFI_GUID *UniqueId OPTIONAL, =20 + IN UINT32 Delay =20 + ) =20 +{ =20 + DELAYED_DISPATCH_TABLE *DelayedDispatchTable; =20 + DELAYED_DISPATCH_ENTRY *Entry; =20 + =20 + // Check input parameters =20 + if ((NULL =3D=3D Function) || (Delay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) || (NULL =3D=3D This)) { =20 + DEBUG ((DEBUG_ERROR, "%a Invalid parameter\n", __func__)); =20 + return EFI_INVALID_PARAMETER; =20 + } =20 + =20 + // Get delayed dispatch table =20 + DelayedDispatchTable =3D GetDelayedDispatchTable (); =20 + if (NULL =3D=3D DelayedDispatchTable) { =20 + DEBUG ((DEBUG_ERROR, "%a Unable to locate dispatch table\n", __func__)); =20 + return EFI_UNSUPPORTED; =20 + } =20 + =20 + // Check for available entry slots =20 + if (DelayedDispatchTable->Count >=3D FixedPcdGet32 (PcdDelayedDispatchMaxEntries)) { =20 + ASSERT (DelayedDispatchTable->Count < FixedPcdGet32 (PcdDelayedDispatchMaxEntries)); =20 + DEBUG ((DEBUG_ERROR, "%a Too many entries requested\n", __func__)); =20 + return EFI_OUT_OF_RESOURCES; =20 + } =20 + =20 + Entry =3D &(DelayedDispatchTable->Entry[DelayedDispatchTable->Count]); =20 + Entry->Function =3D Function; =20 + Entry->Context =3D Context; =20 + Entry->DispatchTime =3D GET_TIME_IN_US () + Delay; =20 + if (NULL !=3D UniqueId) { =20 + CopyGuid (&Entry->UniqueId, UniqueId); =20 + } else { =20 + ZeroMem (&Entry->UniqueId, sizeof (EFI_GUID)); =20 + } =20 + =20 + Entry->MicrosecondDelay =3D Delay; =20 + DelayedDispatchTable->Count++; =20 + =20 + DEBUG ((DEBUG_INFO, "%a Adding dispatch Entry\n", __func__)); =20 + DEBUG ((DEBUG_INFO, " Requested Delay =3D %d\n", Delay)); =20 + DEBUG ((DEBUG_INFO, " Trigger Time =3D %d\n", Entry->DispatchTime)); =20 + DEBUG ((DEBUG_INFO, " Context =3D 0x%08lx\n", Entry->Context)); =20 + DEBUG ((DEBUG_INFO, " Function =3D %p\n", Entry->Function)); =20 + DEBUG ((DEBUG_INFO, " GuidHandle =3D %g\n", &(Entry->UniqueId))); =20 + =20 + if (0 =3D=3D Delay) { =20 + // Force early dispatch point =20 + DelayedDispatchDispatcher (DelayedDispatchTable, NULL); =20 + } =20 + =20 + return EFI_SUCCESS; =20 +} =20 + =20 +/** =20 + DelayedDispatchDispatcher =20 + =20 + ayed Dispach cycle (ie one pass) through each entry, calling functions when their =20 + e has expired. When UniqueId is specified, if there are any of the specified entries =20 + the dispatch queue during dispatch, repeat the DelayedDispatch cycle. =20 + =20 + @param DelayedDispatchTable Pointer to dispatch table =20 + @param OPTIONAL UniqueId used to insure particular time is met. =20 + =20 + @return BOOLEAN =20 +**/ =20 +BOOLEAN =20 +DelayedDispatchDispatcher ( =20 + IN DELAYED_DISPATCH_TABLE *DelayedDispatchTable, =20 + IN EFI_GUID *UniqueId OPTIONAL =20 + ) =20 +{ =20 + BOOLEAN Dispatched; =20 + UINT32 TimeCurrent; =20 + UINT32 MaxDispatchTime; =20 + UINTN Index1; =20 + BOOLEAN UniqueIdPresent; =20 + DELAYED_DISPATCH_ENTRY *Entry; =20 + =20 + Dispatched =3D FALSE; =20 + UniqueIdPresent =3D TRUE; =20 + MaxDispatchTime =3D GET_TIME_IN_US () + FixedPcdGet32 (PcdDelayedDispatchCompletionTimeoutUs); =20 + while ((DelayedDispatchTable->Count > 0) && (UniqueIdPresent)) { =20 + UniqueIdPresent =3D FALSE; =20 + DelayedDispatchTable->DispCount++; =20 + =20 + // If dispatching is messed up, clear DelayedDispatchTable and exit. =20 + TimeCurrent =3D GET_TIME_IN_US (); =20 + if (TimeCurrent > MaxDispatchTime) { =20 + DEBUG ((DEBUG_ERROR, "%a - DelayedDispatch Completion timeout!\n", __func__)); =20 + ReportStatusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE), (EFI_SOFTWARE_PEI_CORE | EFI_SW_EC_ABORTED)); =20 + ASSERT (FALSE); =20 + DelayedDispatchTable->Count =3D 0; =20 + break; =20 + } =20 + =20 + // Check each entry in the table for possible dispatch =20 + for (Index1 =3D 0; Index1 < DelayedDispatchTable->Count;) { =20 + Entry =3D &(DelayedDispatchTable->Entry[Index1]); =20 + // If UniqueId is present, insure there is an additional check of the table. =20 + if (NULL !=3D UniqueId) { =20 + if (CompareGuid (UniqueId, &Entry->UniqueId)) { =20 + UniqueIdPresent =3D TRUE; =20 + } =20 + } =20 + =20 + TimeCurrent =3D GET_TIME_IN_US (); =20 + if (TimeCurrent >=3D Entry->DispatchTime) { =20 + // Time expired, invoked the function =20 + DEBUG (( =20 + DEBUG_ERROR, =20 + "Delayed dispatch entry %d @ %p, Target=3D%d, Act=3D%d Disp=3D%d\n", =20 + Index1, =20 + Entry->Function, =20 + Entry->DispatchTime, =20 + TimeCurrent, =20 + DelayedDispatchTable->DispCount =20 + )); =20 + Dispatched =3D TRUE; =20 + Entry->MicrosecondDelay =3D 0; =20 + Entry->Function ( =20 + &Entry->Context, =20 + &Entry->MicrosecondDelay =20 + ); =20 + DEBUG ((DEBUG_ERROR, "Delayed dispatch Function returned delay=3D%d\n", Entry->MicrosecondDelay)); =20 + if (0 =3D=3D Entry->MicrosecondDelay) { =20 + // NewTime =3D 0 =3D delete this entry from the table =20 + DelayedDispatchTable->Count--; =20 + CopyMem (Entry, Entry+1, sizeof (DELAYED_DISPATCH_ENTRY) * (DelayedDispatchTable->Count - Index1)); =20 + } else { =20 + if (Entry->MicrosecondDelay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) { =20 + DEBUG ((DEBUG_ERROR, "%a Illegal new delay %d requested\n", __func__, Entry->MicrosecondDelay)); =20 + ASSERT (FALSE); =20 + Entry->MicrosecondDelay =3D FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs); =20 + } =20 + =20 + // NewTime !=3D 0 - update the time from us to Dispatch time =20 + Entry->DispatchTime =3D GET_TIME_IN_US () + Entry->MicrosecondDelay; =20 + Index1++; =20 + } =20 + } else { =20 + Index1++; =20 + } =20 + } =20 + } =20 + =20 + return Dispatched; =20 +} =20 + =20 +/** =20 + Wait on a registered Delayed Dispatch unit that has a UniqueId. Continue =20 + to dispatch all registered delayed dispatch entries until *ALL* entries with =20 + UniqueId have completed. =20 + =20 + @param[in] This The Delayed Dispatch PPI pointer. =20 + @param[in] UniqueId UniqueId of delayed dispatch entry. =20 + =20 + @retval EFI_SUCCESS The operation succeeds. =20 + @retval EFI_INVALID_PARAMETER The parameters are invalid. =20 + =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchWaitOnUniqueId ( =20 + IN EFI_DELAYED_DISPATCH_PPI *This, =20 + IN EFI_GUID *UniqueId =20 + ) =20 +{ =20 + PERF_FUNCTION_BEGIN (); =20 + DELAYED_DISPATCH_TABLE *DelayedDispatchTable; =20 + =20 + // Get delayed dispatch table =20 + DelayedDispatchTable =3D GetDelayedDispatchTable (); =20 + if (NULL =3D=3D DelayedDispatchTable) { =20 + PERF_FUNCTION_END (); =20 + return EFI_UNSUPPORTED; =20 + } =20 + =20 + if ((NULL =3D=3D UniqueId) || (IsZeroGuid (UniqueId))) { =20 + ASSERT (FALSE); =20 + PERF_FUNCTION_END (); =20 + return EFI_UNSUPPORTED; =20 + } =20 + =20 + DEBUG ((DEBUG_INFO, "Delayed dispatch on %g. Count=3D%d, DispatchCount=3D%d\n", UniqueId, DelayedDispatchTable->Count, DelayedDispatchTable->DispCount)); =20 + PERF_EVENT_SIGNAL_BEGIN (UniqueId); =20 + DelayedDispatchDispatcher (DelayedDispatchTable, UniqueId); =20 + PERF_EVENT_SIGNAL_END (UniqueId); =20 + =20 + PERF_FUNCTION_END (); =20 + return EFI_SUCCESS; =20 +} =20 + =20 +/** =20 + DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch =20 + entries are complete before exiting PEI. =20 + =20 + @param[in] PeiServices - Pointer to PEI Services Table. =20 + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that =20 + caused this function to execute. =20 + @param[in] Ppi - Pointer to the PPI data associated with this function. =20 + =20 + @retval EFI_STATUS - Always return EFI_SUCCESS =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchOnEndOfPei ( =20 + IN EFI_PEI_SERVICES **PeiServices, =20 + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, =20 + IN VOID *Ppi =20 + ) =20 +{ =20 + DELAYED_DISPATCH_TABLE *DelayedDispatchTable; =20 + =20 + // Get delayed dispatch table =20 + DelayedDispatchTable =3D GetDelayedDispatchTable (); =20 + if (NULL =3D=3D DelayedDispatchTable) { =20 + return EFI_UNSUPPORTED; =20 + } =20 + =20 + PERF_INMODULE_BEGIN ("PerfDelayedDispatchEndOfPei"); =20 + while (DelayedDispatchTable->Count > 0) { =20 + DelayedDispatchDispatcher (DelayedDispatchTable, NULL); =20 + } =20 + =20 + DEBUG ((DEBUG_ERROR, "%a Count of dispatch cycles is %d\n", __func__, DelayedDispatchTable->DispCount)); =20 + PERF_INMODULE_END ("PerfDelayedDispatchEndOfPei"); =20 + =20 + return EFI_SUCCESS; =20 +} =20 + =20 /** =20 =20 =20 Discover all PEIMs and optional Apriori file in one FV. There is at most one =20 @@ -1365,12 +1692,31 @@ PeiDispatcher ( EFI_PEI_FILE_HANDLE SaveCurrentFileHandle; =20 EFI_FV_FILE_INFO FvFileInfo; =20 PEI_CORE_FV_HANDLE *CoreFvHandle; =20 + EFI_HOB_GUID_TYPE *GuidHob; =20 + UINT32 TableSize; =20 =20 =20 PeiServices =3D (CONST EFI_PEI_SERVICES **)&Private->Ps; =20 PeimEntryPoint =3D NULL; =20 PeimFileHandle =3D NULL; =20 EntryPoint =3D 0; =20 =20 =20 + if (NULL =3D=3D Private->DelayedDispatchTable) { =20 + GuidHob =3D GetFirstGuidHob (&gEfiDelayedDispatchTableGuid); =20 + if (NULL !=3D GuidHob) { =20 + Private->DelayedDispatchTable =3D (DELAYED_DISPATCH_TABLE *)(GET_GUID_HOB_DATA (GuidHob)); =20 + } else { =20 + TableSize =3D sizeof (DELAYED_DISPATCH_TABLE) + ((FixedPcdGet32 (PcdDelayedDispatchMaxEntries) - 1) * sizeof (DELAYED_DISPATCH_ENTRY)); =20 + Private->DelayedDispatchTable =3D BuildGuidHob (&gEfiDelayedDispatchTableGuid, TableSize); =20 + if (NULL !=3D Private->DelayedDispatchTable) { =20 + ZeroMem (Private->DelayedDispatchTable, TableSize); =20 + Status =3D PeiServicesInstallPpi (&mDelayedDispatchDesc); =20 + ASSERT_EFI_ERROR (Status); =20 + Status =3D PeiServicesNotifyPpi (&mDelayedDispatchNotifyDesc); =20 + ASSERT_EFI_ERROR (Status); =20 + } =20 + } =20 + } =20 + =20 if ((Private->PeiMemoryInstalled) && =20 (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) || =20 (Private->HobList.HandoffInformationTable->BootMode !=3D BOOT_ON_S3_RESUME) || =20 @@ -1621,6 +1967,13 @@ PeiDispatcher ( } =20 } =20 } =20 + =20 + // Dispatch pending delalyed dispatch requests =20 + if (NULL !=3D Private->DelayedDispatchTable) { =20 + if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) { =20 + ProcessDispatchNotifyList (Private); =20 + } =20 + } =20 } =20 =20 =20 // =20 diff --git a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c index bf1719d7941a..e5643adf7027 100644 --- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c +++ b/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c @@ -277,6 +277,9 @@ PeiCore ( OldCoreData->TempFileHandles =3D (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset); =20 } =20 =20 =20 + // Force relocating the dispatch table =20 + OldCoreData->DelayedDispatchTable =3D NULL; =20 + =20 // =20 // Fixup for PeiService's address =20 // =20 diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h index 556beddad533..3b8bbe7f25a1 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.h +++ b/MdeModulePkg/Core/Pei/PeiMain.h @@ -11,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent =20 =20 #include =20 #include =20 +#include =20 +#include =20 #include =20 #include =20 #include =20 @@ -41,6 +43,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include =20 #include =20 #include =20 +#include =20 #include =20 #include =20 #include =20 @@ -207,6 +210,29 @@ EFI_STATUS =20 =20 #define PEI_CORE_HANDLE_SIGNATURE SIGNATURE_32('P','e','i','C') =20 =20 =20 +#define GET_TIME_IN_US() ((UINT32)DivU64x32(GetTimeInNanoSecond(GetPerformanceCounter ()), 1000)) =20 + =20 +// =20 +// Internal structure for delayed dispatch entries. =20 +// =20 +#pragma pack (push, 1) =20 + =20 +typedef struct { =20 + EFI_GUID UniqueId; =20 + UINT64 Context; =20 + EFI_DELAYED_DISPATCH_FUNCTION Function; =20 + UINT32 DispatchTime; =20 + UINT32 MicrosecondDelay; =20 +} DELAYED_DISPATCH_ENTRY; =20 + =20 +typedef struct { =20 + UINT32 Count; =20 + UINT32 DispCount; =20 + DELAYED_DISPATCH_ENTRY Entry[1]; // Actual size based on PCD PcdDelayedDispatchMaxEntries; =20 +} DELAYED_DISPATCH_TABLE; =20 + =20 +#pragma pack (pop) =20 + =20 /// =20 /// Pei Core private data structure instance =20 /// =20 @@ -307,6 +333,11 @@ struct _PEI_CORE_INSTANCE { // Those Memory Range will be migrated into physical memory. =20 // =20 HOLE_MEMORY_DATA HoleData[HOLE_MAX_NUMBER]; =20 + =20 + // =20 + // Table of delayed dispatch requests =20 + // =20 + DELAYED_DISPATCH_TABLE *DelayedDispatchTable; =20 }; =20 =20 =20 /// =20 @@ -2038,4 +2069,49 @@ PeiReinitializeFv ( IN PEI_CORE_INSTANCE *PrivateData =20 ); =20 =20 =20 +/** =20 +Register a callback to be called after a minimum delay has occurred. =20 + =20 +This service is the single member function of the EFI_DELAYED_DISPATCH_PPI =20 + =20 + @param[in] This Pointer to the EFI_DELAYED_DISPATCH_PPI instance =20 + @param[in] Function Function to call back =20 + @param[in] Context Context data =20 + @param[in] UniqueId GUID for this Delayed Dispatch request. =20 + @param[in] Delay Delay interval =20 + =20 + @retval EFI_SUCCESS Function successfully loaded =20 + @retval EFI_INVALID_PARAMETER One of the Arguments is not supported =20 + @retval EFI_OUT_OF_RESOURCES No more entries =20 + =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchRegister ( =20 + IN EFI_DELAYED_DISPATCH_PPI *This, =20 + IN EFI_DELAYED_DISPATCH_FUNCTION Function, =20 + IN UINT64 Context, =20 + IN EFI_GUID *UniqueId OPTIONAL, =20 + IN UINT32 Delay =20 + ); =20 + =20 +/** =20 + Wait on a registered Delayed Dispatch unit that has a UniqueId. Continue =20 + to dispatch all registered delayed dispatch entries until *ALL* entries with =20 + UniqueId have completed. =20 + =20 + @param[in] This The Delayed Dispatch PPI pointer. =20 + @param[in] UniqueId UniqueId of delayed dispatch entry. =20 + =20 + @retval EFI_SUCCESS The operation succeeds. =20 + @retval EFI_INVALID_PARAMETER The parameters are invalid. =20 + =20 +**/ =20 +EFI_STATUS =20 +EFIAPI =20 +PeiDelayedDispatchWaitOnUniqueId ( =20 + IN EFI_DELAYED_DISPATCH_PPI *This, =20 + IN EFI_GUID *UniqueId =20 + ); =20 + =20 #endif =20 diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf index 0cf357371a16..73738c939ac7 100644 --- a/MdeModulePkg/Core/Pei/PeiMain.inf +++ b/MdeModulePkg/Core/Pei/PeiMain.inf @@ -66,6 +66,7 @@ [LibraryClasses] PeCoffLib =20 PeiServicesTablePointerLib =20 PcdLib =20 + TimerLib =20 =20 =20 [Guids] =20 gPeiAprioriFileNameGuid ## SOMETIMES_CONSUMES ## File =20 @@ -78,6 +79,7 @@ [Guids] gEfiFirmwareFileSystem3Guid =20 gStatusCodeCallbackGuid =20 gEdkiiMigratedFvInfoGuid ## SOMETIMES_PRODUCES ## HOB =20 + gEfiDelayedDispatchTableGuid ## SOMETIMES_PRODUCES ## HOB =20 =20 =20 [Ppis] =20 gEfiPeiStatusCodePpiGuid ## SOMETIMES_CONSUMES # PeiReportStatusService is not ready if this PPI doesn't exist =20 @@ -100,6 +102,8 @@ [Ppis] gEfiPeiReset2PpiGuid ## SOMETIMES_CONSUMES =20 gEfiSecHobDataPpiGuid ## SOMETIMES_CONSUMES =20 gEfiPeiCoreFvLocationPpiGuid ## SOMETIMES_CONSUMES =20 + gEfiPeiDelayedDispatchPpiGuid ## SOMETIMES_CONSUMES =20 [Liming] Here should PRODUCES.=20 =20 + gEfiEndOfPeiSignalPpiGuid ## CONSUMES =20 =20 =20 [Pcd] =20 gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize ## CONSUMES =20 @@ -112,6 +116,9 @@ [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot ## CONSUMES =20 gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack ## CONSUMES =20 =20 gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolu mes ## CONSUMES =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs ## CONSUMES =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeout Us ## CONSUMES =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxEntries ## CONSUMES =20 =20 =20 # [BootMode] =20 # S3_RESUME ## SOMETIMES_CONSUMES =20 diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 0ff058b0a9da..2f4bd2f2b773 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -418,6 +418,9 @@ [Guids] ## Include/Guid/MigratedFvInfo.h =20 gEdkiiMigratedFvInfoGuid =3D { 0xc1ab12f7, 0x74aa, 0x408d, { 0xa2, 0xf4, 0xc6, 0xce, 0xfd, 0x17, 0x98, 0x71 } } =20 =20 =20 + ## Delayed Dispatch table GUID =20 + gEfiDelayedDispatchTableGuid =3D { 0x4b733449, 0x8eff, 0x488c, {0x92, 0x1a, 0x15, 0x4a, 0xda, 0x25, 0x18, 0x07}} =20 + [Liming] This GUID is only used in PeiMain. I suggest to define the global GUID variable in PeiCore for this usage. =20 =20 # =20 # GUID defined in UniversalPayload =20 # =20 @@ -991,6 +994,18 @@ [PcdsFixedAtBuild] # @ValidList 0x80000006 | 0x03058002 =20 =20 gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|U INT32|0x30001040 =20 =20 =20 + ## Delayed Dispatch Maximum Delay in us (microseconds) =20 + # Maximum delay for any particular delay request - 5 seconds =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs|500000 0|UINT32|0x3000104A =20 + =20 + ## Delayed Dispatch timeout in us (microseconds) =20 + # Maximum delay when waiting for completion (ie EndOfPei) - 10 seconds =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeout Us|10000000|UINT32|0x3000104B =20 + =20 + ## Delayed Dispatch Max Entries =20 + # Maximum number of delayed dispatch entries =20 + gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxEntries|8|UINT3 2|0x3000104C =20 + [Liming] I suggest to define MACRO in PeiCore for them. If there is real usage model, new PCD can be introduced later.=20 =20 Thanks Liming =20 ## Mask to control the NULL address detection in code for different phases. =20 # If enabled, accessing NULL address in UEFI or SMM code can be caught.

=20 # BIT0 - Enable NULL pointer detection for UEFI.
=20 -- 2.41.0.windows.2 =20 =20 =20 =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 (#107447): https://edk2.groups.io/g/devel/message/107447 Mute This Topic: https://groups.io/mt/100499790/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- ------=_NextPart_000_003D_01D9C543.6BFD8DC0 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable

Kun:

=C2=A0PcdDelayedDispatchMaxEntries is not required. Th= e required Entry number can be increased at boot time. You can see MaxFvCou= nt in PrivateData that is increased by FV_GROWTH_STEP

=

 

T= hanks

Liming<= /p>

=E5=8F=91=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io <devel@edk2.groups.io> =E4= =BB=A3=E8=A1=A8 Kun Qin
=E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4= : 2023=E5=B9=B48=E6=9C=881=E6=97=A5 12:16=E6=94=B6=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io; gaoliming@byosoft.com.cn
= =E6=8A=84=E9=80=81: 'Jian = J Wang' <jian.j.wang@intel.com>; 'Dandan Bi' <dandan.bi@intel.com&= gt;; 'Debkumar De' <debkumar.de@intel.com>; 'Catharine West' <cath= arine.west@intel.com>; 'Mike Turner' <mikeyt@pobox.com>
= =E4=B8=BB=E9=A2=98: Re:= [edk2-devel] =E5=9B=9E=E5=A4=8D: [PATCH v1 3/4] = MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch

 

Hi Liming,

Thanks fo= r the feedback.

Per your feedback (I suggest to define MACRO in PeiC= ore for them. If there is real usage model, new PCD can be introduced later= .) on the following new PCDs:

= gEfiMdeModulePkgTokenSpaceGuid.PcdDela= yedDispatchMaxDelayUs
gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeou= tUs
gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxEntries

Given t= his feature has been used internally at Project MU for a while, I
collec= ted some feedback from the consumer platforms:

- Delayed dispatch is a feature that can be used for power u= p sequence, and
thus the value of maximum entries in this case can depen= d on the number of PCI
devices on the platform, and thus hardcoding the = value as a macro definition will
limit the usage and we might come to up= date it very soon.

- There is al= ready usage on our platforms that would override the timeout PCDs
to bas= ed on the firmware builds. For example, on a test build, we might register = extra
entries to the PPI and thus extend the completion timeout.

= I agree with your comments on other fronts. Please let me know if you have = further
concerns regarding the PCDs above. I can send out an updated ver= sion after your input
on those.

Thanks,
Kun
<= /p>

On 7/24/2023 7:17 PM, gaoli= ming via groups.io wrote:

Kun: 
=C2=A0=C2=A0I add my comments below.=
 
 
-----=E9=82=AE=E4=BB=B6=E5=8E=9F=E4=BB=B6-----
=E5=8F=91=E4=BB=B6=E4=BA=BA: Kun Qin <kuqin12@gmail.c=
om>
=E5=8F=91=E9=80=81=E6=97=B6=E9=97=B4=
: 2023=E5=B9=B47=E6=9C=
=8821=E6=97=A5 5:07=
=E6=94=B6=E4=BB=B6=E4=BA=BA: devel@edk2.groups.io=
=E6=8A=84=E9=80=81: Jian J Wang <jian.j.wang@intel.com>; Dandan Bi
<dandan.bi@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
Debkumar De <debkumar.de@intel.com>; Catharine West
<catharine.west@intel.com>; Mike Turner <mikeyt@pobox.com>
=E4=B8=
=BB=E9=A2=98: [PATCH v1 3/4] MdeModulePkg: PeiMain: Intr=
oduce implementation of
dela=
yed dispatch
 
REF: https://bugzilla.tianocore.org/show_bug.=
cgi?id=3D4496
 =
;
This change adds the implementa=
tion that fits the needs and description
of PI spec defined Delayed Dispatch PPI in Pei Core.
 
The PPI would allow minimal delay for registered callbacks=
. As well as
allowing other =
functions to wait for GUIDed delayed dispatch callbacks.<=
/pre>
 
Cc: Jian J Wang <jian.=
j.wang@intel.com>
Cc:=
 Dandan Bi <dandan.bi@intel.com&g=
t;
Cc: Liming Gao <gaoliming@byosoft.com.cn><=
o:p>
Cc: Debkumar De <debkumar.de@intel.com>
Cc: Catharine West <catharine.west@intel.com>
 
Co-authored-by: Mike Turner =
<mikeyt@pobox.com>
Signed-off-by: Kun Qin <kuqin12@gm=
ail.com>
---
 MdeModulePkg/Core/Pei/Dispatcher/Di=
spatcher.c | 353
+++++++++++=
+++++++++
 MdeModulePkg/Core=
/Pei/PeiMain/PeiMain.c=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 3 =
+
 MdeModulePkg/Core/Pei/Pei=
Main.h=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0|=C2=A0 76 +++++
 MdeModulePkg/Core/Pei/PeiMain.inf=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 |=C2=A0=C2=A0 7 +
 MdeModulePkg/MdeModulePkg.dec=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 |=C2=A0 15 +
 5 fi=
les changed, 454 insertions(+)
 
diff --git a/MdeMo=
dulePkg/Core/Pei/Dispatcher/Dispatcher.c
b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index 5f32ebb560ae..50e59bdbe732 100644
--- a/MdeModulePkg/Core/Pei/Di=
spatcher/Dispatcher.c
+++ b/=
MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
<=
span lang=3DEN-US>@@ -3,12 +3,339 @@
 
 <=
/o:p>
 Copyright (c) 2006 - 2019, Intel=
 Corporation. All rights reserved.<BR>
 
 (C)=
 Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 
=
+Copyright (c) Microsoft Corporation.<=
/pre>
 
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 
 
 **/
 
=
 
 
 #include "PeiMain.h"
 
 
 =
;
+/**
 
=
+=C2=A0 DelayedDispatchDispatcher
 
+
 
+=C2=A0 ayed Dispach cycle (ie one pass) through each entry, c=
alling functions
when their<=
o:p>
 
+=C2=A0 e has expired.=C2=A0 When UniqueId is spe=
cified, if there are any of the
specified entries
&=
nbsp;
+=C2=A0 the dispatch queue =
during dispatch, repeat the DelayedDispatch cycle.
<= pre> 
+
 =
[Liming] Above comments are inco=
mplete. Please update. 
 
+=C2=A0 @param DelayedDispatchTable=C2=A0=
 Pointer to dispatch table
<=
o:p> 
+=C2=A0 @param OPTIONA=
L=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 UniqueId used to insure particular
time is met.
<=
o:p> 
+
 
+=C2=A0 @return BOOLEAN
 
+**/
 
+BOOLEAN
&n=
bsp;
+DelayedDispatchDispatcher (=
 
+=C2=A0 IN DELAYED_DISPATCH_TABLE=C2=A0 *Delayed=
DispatchTable,
 
+=C2=A0 IN EFI_GUID=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 *UniqueId=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 OPTI=
ONAL
 
+=C2=A0 );
 
+<=
/o:p>
 
+/**
 
+=C2=A0 DelayedDispatch=
 End of PEI callback function. Insure that all of the
delayed dispatch
 
+=C2=
=A0 entries are complete before exiting PEI.
 
+
 
=
+=C2=A0 @param[in] PeiServices=C2=A0=C2=A0 - Pointe=
r to PEI Services Table.
 
+=C2=A0 @param[in] Notif=
yDesc=C2=A0=C2=A0=C2=A0 - Pointer to the descriptor for the
Notification=
event that
 
+=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ca=
used this function to execute.
 
+=C2=A0 @param[in]=
 Ppi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - Pointer =
to the PPI data associated with this
function.
&nbs=
p;
+
=
 
+=
=C2=A0 @retval EFI_STATUS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - Always retu=
rn EFI_SUCCESS
 
+**/
<=
span lang=3DEN-US> 
+EF=
I_STATUS
 
+EFIAPI
 
+PeiDe=
layedDispatchOnEndOfPei (
 
+=C2=A0 IN EFI_PEI_SERV=
ICES=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 **PeiServi=
ces,
 
+=C2=A0 IN EFI_PEI_NOTIFY_DESCRIPTOR=C2=A0 *=
NotifyDesc,
 
+=C2=A0 IN VOID=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *Ppi
 
+=C2=A0=
 );
 =
+
 
+EFI_DELAYED_DISP=
ATCH_PPI=C2=A0 mDelayedDispatchPpi=C2=A0 =3D
{ PeiDelayedDispatchRegister, PeiDelayedDispatchWaitOnUniq=
ueId };
 
+EFI_PEI_PPI_DESCRIPTOR=C2=A0=C2=A0=C2=A0=
 mDelayedDispatchDesc =3D {
=
 
+=C2=A0 (EFI_PEI_PPI_=
DESCRIPTOR_PPI |
EFI_PEI_PPI=
_DESCRIPTOR_TERMINATE_LIST),
 
+=C2=A0 &gEfiPei=
DelayedDispatchPpiGuid,
 
+=C2=A0 &mDelayedDisp=
atchPpi
 
+};
 
+
 
+EFI_PEI_NOTIFY_DESCRIPTOR=C2=A0 mDelayedDispatchNotifyDes=
c =3D {
 
+=C2=A0 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CAL=
LBACK |
EFI_PEI_PPI_DESCRIPT=
OR_TERMINATE_LIST,
&nbs=
p;
+=C2=A0 &gEfiEndOfPeiSigna=
lPpiGuid,
 <=
/span>
+=C2=A0 PeiDelayedDispatchOnEndOfPei
 
=
+};
=
 
+
 
+/**
 
+=C2=A0 Helper function to look up =
DELAYED_DISPATCH_TABLE published in HOB.
 
+
 
+=C2=A0 @return Pointer to DELAYED_DISPATCH_TABLE from = HOB
 =
+**/
 
+DELAYED_DIS=
PATCH_TABLE *
 
+GetDelayedDispatchTable (
 
<=
span lang=3DEN-US>+=C2=A0 VOID
 
+=C2=A0 )
 
<=
span lang=3DEN-US>+{
&n=
bsp;
+=C2=A0 EFI_HOB_GUID_TYPE=C2=
=A0 *GuidHob;
 
+
 
+=C2=A0=
 GuidHob =3D GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
 
+=C2=A0 if (NULL =3D=3D GuidHob) {
=
 
+=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "Delayed Dispatch PPI ERRO=
R - Delayed
Dispatch Hob not=
 available.\n"));
=
 
+=C2=A0=C2=A0=C2=A0 ASSERT=
 (FALSE);
 <=
/span>
+=C2=A0=C2=A0=C2=A0 return NULL;
 
+=C2=A0 }
 
+=
 
+=C2=A0 return (DELAYED_DISPATCH_TABLE *)GET_GUID_HOB_DATA (GuidHo=
b);
 =
+}
 
+
 
+/**
 =
+Register a callback to be calle=
d after a minimum delay has occurred.
 
+
 
+This service is the single member function of the
EFI_DELAYED_DISPATCH_PPI=
 
+
 =
;
+=C2=A0 @param[in] This=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Pointer to the EFI_D=
ELAYED_DISPATCH_PPI
instance=
 
+=C2=A0 @param[in] Function=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0 Function to call back
 
+=C2=A0 @pa=
ram[in] Context=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Context data=
 
+=C2=A0 @param[in] UniqueId=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 GUID for this Delayed Dispatch request.
 
+=C2=A0 @param[in] Delay=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 Delay interval
 
+
 
+=C2=A0 @retval EFI_SUCCESS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Function successfully loaded
 
<= pre>+=C2=A0 @retval EFI_INVALID_PARAMETER=C2=A0=C2=A0=C2= =A0=C2=A0 One of the Arguments is not
supported
&nb=
sp;
+=C2=A0 @retval EFI_OUT_OF_RE=
SOURCES=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 No more entries
 
+
 
+**/
 
+EFI_STATUS=
 
+EFIAPI
 
+PeiDelayedD=
ispatchRegister (
 =
;
+=C2=A0 IN=C2=A0 EFI_DELAYED_DI=
SPATCH_PPI=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *This,
 
+=C2=A0 IN=C2=A0 EFI_DELAYED_DISPATCH_FUNCTION=C2=A0 Function,
 
=
+=C2=A0 IN=C2=A0 UINT64=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Context,
<=
span lang=3DEN-US> 
+=
=C2=A0 IN=C2=A0 EFI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 *UniqueId=C2=A0=C2=A0 OPTIONAL,
 
+=C2=A0 IN=
=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0Delay
 
+=C2=A0 )
<= pre> 
+{
 
+=C2=A0 DELAYED_DISPATCH_TABLE=C2=A0 *Delaye=
dDispatchTable;
 <=
/o:p>
+=C2=A0 DELAYED_DISPATCH_ENTRY=C2=
=A0 *Entry;
 
+
 
+=C2=A0 /=
/ Check input parameters
 
+=C2=A0 if ((NULL =3D=3D=
 Function) || (Delay > FixedPcdGet32
(PcdDelayedDispatchMaxDelayUs)) || (NULL =3D=3D This)) {
 
+=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "%a Inval= id parameter\n", __func__));
 
+=C2=A0=C2=A0=
=C2=A0 return EFI_INVALID_PARAMETER;
 
+=C2=A0 }
 
=
+
 
+=C2=A0 // Get delayed =
dispatch table
 
+=C2=A0 DelayedDispatchTable =3D G=
etDelayedDispatchTable ();
<=
o:p> 
+=C2=A0 if (NULL =3D=
=3D DelayedDispatchTable) {
=
 
+=C2=A0=C2=A0=C2=A0 D=
EBUG ((DEBUG_ERROR, "%a Unable to locate dispatch table\n",<=
/o:p>
__func__));
 
+=C2=A0=C2=A0=C2=A0 return EFI_UNSUPPORTED;
 
=
+=C2=A0 }
 <=
/span>
+
 
+=C2=A0 // =
Check for available entry slots
 
+=C2=A0 if (Delay=
edDispatchTable->Count >=3D FixedPcdGet32
(PcdDelayedDispatchMaxEntries)) {
 
+=C2=A0=C2=A0=C2=A0 ASSERT (DelayedDispatchTable->Count < FixedP=
cdGet32
(PcdDelayedDispatchM=
axEntries));
 
+=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ER=
ROR, "%a Too many entries requested\n",
__func__));
 
+=C2=A0=C2=A0=
=C2=A0 return EFI_OUT_OF_RESOURCES;
 
+=C2=A0 }
 
=
+
 
+=C2=A0 Entry=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 =3D
&(DelayedDispatchTa=
ble->Entry[DelayedDispatchTable->Count]);
 
+=
=C2=A0 Entry->Function=C2=A0=C2=A0=C2=A0=C2=A0 =3D Function;<=
/span>
 
+=C2=A0 Entry->Context=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D =
Context;
 
+=C2=A0 Entry->DispatchTime =3D GET_T=
IME_IN_US () + Delay;
&=
nbsp;
+=C2=A0 if (NULL !=3D Uniqu=
eId) {
 
+=C2=A0=C2=A0=C2=A0 CopyGuid (&Entry-&=
gt;UniqueId, UniqueId);
 
+=C2=A0 } else {
 
<=
span lang=3DEN-US>+=C2=A0=C2=A0=C2=A0 ZeroMem (&Entry->UniqueId, siz=
eof (EFI_GUID));
 =
+=C2=A0 }
 
+
 
+=C2=A0 Entry->MicrosecondDelay =3D Dela=
y;
 <=
/pre>
+=C2=A0 DelayedDispatchTable->Count++;=
 
+
 
+=C2=A0 DEBUG ((DEBUG_INF=
O, "%a=C2=A0 Adding dispatch Entry\n", __func__));
 
+=C2=A0 DEBUG ((DEBUG_INFO, "=C2=A0=C2=A0=C2=A0 Requested =
Delay =3D %d\n", Delay));
 
+=C2=A0 DEBUG ((DE=
BUG_INFO, "=C2=A0=C2=A0=C2=A0 Trigger Time =3D %d\n",<=
/span>
Entry->DispatchTime));
 
+=C2=A0 DEBUG ((DEBUG_INFO, "=C2=A0=C2=A0=C2=A0 Context =
=3D 0x%08lx\n", Entry->Context));
 
+=C2=A0=
 DEBUG ((DEBUG_INFO, "=C2=A0=C2=A0=C2=A0 Function =3D %p\n", Entr=
y->Function));
 =
;
+=C2=A0 DEBUG ((DEBUG_INFO, &qu=
ot;=C2=A0=C2=A0=C2=A0 GuidHandle =3D %g\n", &(Entry->UniqueId))=
);
 <=
/pre>
+
 
+=C2=A0 if (0 =3D=
=3D Delay) {
 
+=C2=A0=C2=A0=C2=A0 // Force early d=
ispatch point
 
+=C2=A0=C2=A0=C2=A0 DelayedDispatch=
Dispatcher (DelayedDispatchTable, NULL);
 
+=C2=A0 =
}
 
+
 
+=C2=A0 return EFI_=
SUCCESS;
 
+}
 
+
 
+/**
&=
nbsp;
+=C2=A0 DelayedDispatchDisp=
atcher
 
+
 
+=C2=A0 ayed=
 Dispach cycle (ie one pass) through each entry, calling functions
when their
 
+=C2=A0 e has expired.=C2=A0 When UniqueId is specified, if there are any =
of the
specified entries
 
<= pre>+=C2=A0 the dispatch queue during dispatch, repeat t= he DelayedDispatch cycle.
 
+
 
+=C2=A0 @param DelayedDispatchTable=C2=A0 Pointer to dispatch table
 
=
+=C2=A0 @param OPTIONAL=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 UniqueId used to insure=
 particular
time is met.
 
<= pre>+
 
+=C2=A0 @return BOOLEAN<=
o:p>
 
+**/
 
+BOOLEAN
 
+DelayedDispatchDispatcher (
<=
span lang=3DEN-US> 
+=
=C2=A0 IN DELAYED_DISPATCH_TABLE=C2=A0 *DelayedDispatchTable,
 
+=C2=A0 IN EFI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *UniqueId=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 OPTIONAL
 
+=C2=A0 )
 <=
/o:p>
+{
 
+=C2=
=A0 BOOLEAN=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0Dispatched;
 
+=C2=
=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 TimeCurrent;
 
+=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 MaxDispatchTime;
 
+=C2=A0 UINTN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index1;
 
+=C2=A0 BOOLEAN=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 UniqueIdPresent;<= o:p>
 
+=C2=A0 DELAYED_DISPATCH_ENTRY=C2=A0 *Entry;=
 
+
 
+=C2=A0 Dispatched=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 =3D FALSE;
 
+=C2=A0 Uniq=
ueIdPresent =3D TRUE;
&=
nbsp;
+=C2=A0 MaxDispatchTime =3D=
 GET_TIME_IN_US () + FixedPcdGet32
(PcdDelayedDispatchCompletionTimeoutUs);
 
+=C2=A0 while ((DelayedDispatchTable->Count > 0) && (UniqueI=
dPresent)) {
 
+=C2=A0=C2=A0=C2=A0 UniqueIdPresent =
=3D FALSE;
 =
+=C2=A0=C2=A0=C2=A0 DelayedDispatchTab=
le->DispCount++;
&nb=
sp;
+
 
+=
=C2=A0=C2=A0=C2=A0 // If dispatching is messed up, clear DelayedDispatchTab=
le and exit.
 
+=C2=A0=C2=A0=C2=A0 TimeCurrent =3D=
=C2=A0 GET_TIME_IN_US ();
 
+=C2=A0=C2=A0=C2=A0 if =
(TimeCurrent > MaxDispatchTime) {
 
+=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR, "%a - DelayedDispatch Compl=
etion
timeout!\n", __fu=
nc__));
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ReportSta=
tusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE),
(EFI_SOFTWARE_PEI_CORE | EFI_SW_EC_ABORTED));
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ASSERT (FALSE);
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DelayedDispatchTable->Count=
 =3D 0;
 
+=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0break;
 
=
+=C2=A0=C2=A0=C2=A0 }
<=
span lang=3DEN-US> 
+
 
+=C2=A0=C2=A0=C2=A0 // Check each entry in the tab=
le for possible dispatch
 
+=C2=A0=C2=A0=C2=A0 for =
(Index1 =3D 0; Index1 < DelayedDispatchTable->Count;) {
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry =3D &(DelayedDispatc=
hTable->Entry[Index1]);
<=
o:p> 
+=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 // If UniqueId is present, insure there is an additional check of=
the=
table.
=
 
+=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 if (NULL !=3D UniqueId) {
 
+=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (CompareGuid (UniqueId, &Entry->=
;UniqueId)) {
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 UniqueIdPresent =3D TRUE;
 
+=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
+=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
+=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 TimeCurrent =3D=C2=A0 GET_TIME_IN_=
US ();
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (TimeCu=
rrent >=3D Entry->DispatchTime) {
 
+=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // Time expired, invoked the function<=
o:p>
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG=
 ((
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 DEBUG_ERROR,
 
+=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 "Delayed dispatch entry %d @ %p, Tar=
get=3D%d, Act=3D%d
Disp=3D%d=
\n",
 <=
/span>
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 Index1,
<=
o:p> 
+=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry->Function,
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry->Disp=
atchTime,
 <=
/span>
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 TimeCurrent,
 
+=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DelayedDispatchTable->DispCount<=
o:p>
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 ));
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 Dispatched=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 =3D TRUE;
 
+=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry->MicrosecondDelay =3D 0;
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry->Function=
 (
 <=
/pre>
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 &Entry->Context,=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 &Entry->Microsec=
ondDelay
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 );
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 DEBUG ((DEBUG_ERROR=
, "Delayed dispatch Function returned
delay=3D%d\n", Entry->MicrosecondDelay));=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (0 =3D=3D En=
try->MicrosecondDelay) {
=
 
+=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 // NewTime =3D 0 =3D delete this entry=
 from the table
 <=
/o:p>
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 DelayedDispatchTable->Count--;
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 CopyMem (=
Entry, Entry+1, sizeof (DELAYED_DISPATCH_ENTRY)
* (DelayedDispatchTable->Count - Index1));
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else {<=
/o:p>
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 if (Entry->MicrosecondDelay > FixedPcdGet32
(PcdDelayedDispatchMaxDelayUs)) {
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 DEBUG ((DEBUG_ERROR, "%a Illegal new delay %d
requested\n", __func__, Entry->Microseco=
ndDelay));
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ASSERT (FALSE);
=
 
+=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Entry-&g=
t;MicrosecondDelay =3D FixedPcdGet32
(PcdDelayedDispatchMaxDelayUs);
 
+=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
<= pre> 
+
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 // NewTime !=3D 0 - update the time from us to Dispatch time
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 Entry->DispatchTime =3D=C2=A0 GET_TIME_IN_US () +
Entry->MicrosecondDelay;
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index1++=
;
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } else {
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Index1++;=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
+=C2=A0=C2=A0=C2=A0 }
 
+=C2=A0 }
 
<=
span lang=3DEN-US>+
&nb=
sp;
+=C2=A0 return Dispatched;
 
=
+}
<=
o:p> 
+
 
+/**
 =
+=C2=A0 Wait on a registered Delayed D=
ispatch unit that has a UniqueId.
Continue
 
+=C2=A0 to dispatch all registered=
 delayed dispatch entries until *ALL* entries
with
&nb=
sp;
+=C2=A0 UniqueId have complet=
ed.
 =
+
 
+=C2=A0 @param[in=
]=C2=A0=C2=A0=C2=A0=C2=A0 This=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 The Delayed Dispatch PPI pointer.
 
+=C2=A0 @param[in]=C2=A0=C2=A0=C2=A0=C2=A0 UniqueId=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 UniqueId of delayed dispatch entry.<=
/span>
 
+
 =
+=C2=A0 @retval EFI_SUCCESS=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 The operati=
on succeeds.
 
+=C2=A0 @retval EFI_INVALID_PARAMETE=
R=C2=A0 The parameters are invalid.
 
+=
 
+**/
&n=
bsp;
+EFI_STATUS
 
+EFIAPI
 =
;
+PeiDelayedDispatchWaitOnUnique=
Id (
 
+=C2=A0 IN EFI_DELAYED_DISPATCH_PPI=C2=A0 *T=
his,
 
+=C2=A0 IN EFI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 *UniqueId
 
+=C2=A0 )
 
+{
 =
+=C2=A0 PERF_FUNCTION_BEGIN ();
 
+=C2=A0 DELAYED_DISPATCH_TABLE=C2=A0 *DelayedDispatchTable;
 
=
+
 
+=C2=A0 // Get delayed =
dispatch table
 
+=C2=A0 DelayedDispatchTable =3D G=
etDelayedDispatchTable ();
<=
o:p> 
+=C2=A0 if (NULL =3D=
=3D DelayedDispatchTable) {
=
 
+=C2=A0=C2=A0=C2=A0 P=
ERF_FUNCTION_END ();
&n=
bsp;
+=C2=A0=C2=A0=C2=A0 return E=
FI_UNSUPPORTED;
 <=
/o:p>
+=C2=A0 }
=
 
+
 
+=C2=A0 if ((NULL =3D=3D UniqueId) || (IsZer=
oGuid (UniqueId))) {
&n=
bsp;
+=C2=A0=C2=A0=C2=A0 ASSERT (=
FALSE);
 
+=C2=A0=C2=A0=C2=A0 PERF_FUNCTION_END ();=
 
+=C2=A0=C2=A0=C2=A0 return EFI_UNSUPPORTED;=
 
+=C2=A0 }
 
+
 
+=C2=A0 DEBUG ((DEBUG_INFO, "Delayed dispatch on %g. Count=
=3D%d,
DispatchCount=3D%d\n&=
quot;, UniqueId, DelayedDispatchTable->Count,
DelayedDispatchTable->DispCount));
 
+=C2=A0 PERF_EVENT_SIGNAL_BEGIN (UniqueId);
 
+=C2=A0 DelayedDispatchDispatcher (DelayedDispatchTable, UniqueId);
 
=
+=C2=A0 PERF_EVENT_SIGNAL_END (UniqueId);
 
+
&nbs=
p;
+=C2=A0 PERF_FUNCTION_END ();<=
o:p>
 
+=C2=A0 return EFI_SUCCESS;
 
+}
 
+
 
+/**
 
=
+=C2=A0 DelayedDispatch End of PEI callback function. In=
sure that all of the
delayed=
 dispatch
 <=
/span>
+=C2=A0 entries are complete before exi=
ting PEI.
 <=
/span>
+
 
+=C2=A0 @pa=
ram[in] PeiServices=C2=A0=C2=A0 - Pointer to PEI Services Table.=
 
+=C2=A0 @param[in] NotifyDesc=C2=A0=C2=A0=C2=A0 - Pointer t=
o the descriptor for the
Notification
event that=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 caused this function to execute.<=
/o:p>
 
+=C2=A0 @param[in] Ppi=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - Pointer to the PPI data associated with th= is
function.
 
+
 
+=C2=A0 @retval EFI_STATUS=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 - Always return EFI_SUCCESS
 
+**/
 
+EFI_STATUS
=
 
+EFIAPI
 =
+PeiDelayedDispatchOnEndOfPei (
 
+=C2=A0 IN EFI_PEI_SERVICES=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 **PeiServices,
 
=
+=C2=A0 IN EFI_PEI_NOTIFY_DESCRIPTOR=C2=A0 *NotifyDesc,
 
+=C2=A0 IN VOID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 *Ppi
 
+=C2=A0 )
 
+=
{
 
+=C2=A0 DELAYED_DISPATCH_TABLE=C2=A0 *DelayedDi=
spatchTable;
 
+
 
+=C2=A0 =
// Get delayed dispatch table
 
+=C2=A0 DelayedDisp=
atchTable =3D GetDelayedDispatchTable ();
 
+=C2=A0=
 if (NULL =3D=3D DelayedDispatchTable) {
 
+=C2=A0=
=C2=A0=C2=A0 return EFI_UNSUPPORTED;
 
+=C2=A0 }
 
=
+
 
+=C2=A0 PERF_INMODULE_B=
EGIN ("PerfDelayedDispatchEndOfPei");
 
+=
=C2=A0 while (DelayedDispatchTable->Count > 0) {
 
+=C2=A0=C2=A0=C2=A0 DelayedDispatchDispatcher (DelayedDispatchTable, =
NULL);
 
+=C2=A0 }
 
+=
 
+=C2=A0 DEBUG ((DEBUG_ERROR, "%a Count of dispat= ch cycles is %d\n", __func__,
DelayedDispatchTable->DispCount));
=
 
+=
=C2=A0 PERF_INMODULE_END ("PerfDelayedDispatchEndOfPei");
 
=
+
&n=
bsp;
+=C2=A0 return EFI_SUCCESS;<=
o:p>
 
+}
 
+<=
/pre>
 
 /**
 
 
=
 
=
=C2=A0=C2=A0 Discover all PEIMs and optional Apriori file in one FV. There =
is at
most one<=
o:p>
 
@@ -1365,12 +1692,31 @@ PeiDispatcher (
=C2=A0=C2=A0 EFI_PEI_FILE_HANDLE=C2=A0=C2=A0=C2=A0=C2= =A0 SaveCurrentFileHandle;
<=
o:p> 
=C2=A0=C2=A0 EFI_FV_FI=
LE_INFO=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 FvFileInfo;
 
=C2=A0=C2=A0 PEI_CORE_FV_HANDLE=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =
*CoreFvHandle;
 
+=C2=A0 EFI_HOB_GUID_TYPE=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0 *GuidHob;
 
+=C2=A0 UIN=
T32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0TableSize;
 
=
 
 
=C2=A0=C2=A0 PeiServices=C2=A0=C2=A0=C2=A0 =3D =
(CONST EFI_PEI_SERVICES **)&Private->Ps;
 
=
=C2=A0=C2=A0 PeimEntryPoint =3D NULL;
 
=C2=A0=C2=
=A0 PeimFileHandle =3D NULL;
 
=C2=A0=C2=A0 EntryPo=
int=C2=A0=C2=A0=C2=A0=C2=A0 =3D 0;
 
 <=
/o:p>
 
+=C2=A0 if (NULL =3D=3D Private->DelayedDispatchTab= le) {
 
+=C2=A0=C2=A0=C2=A0 GuidHob =3D GetFirstGui=
dHob (&gEfiDelayedDispatchTableGuid);
 
+=C2=A0=
=C2=A0=C2=A0 if (NULL !=3D GuidHob) {
 
+=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 Private->DelayedDispatchTable =3D (DELAYED_DISPATC=
H_TABLE
*)(GET_GUID_HOB_DATA=
 (GuidHob));
 
+=C2=A0=C2=A0=C2=A0 } else {
 
=
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 TableSize=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =3D sizeof
(DELAYED_DISPATCH_TABLE) + ((FixedPcdGet32<=
/pre>
(PcdDelayedDispatchMaxEntries) - 1) * sizeof (=
DELAYED_DISPATCH_ENTRY));
 
+=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 Private->DelayedDispatchTable =3D BuildGuidHob
(&gEfiDelayedDispatchTableGuid, TableSi=
ze);
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (NULL !=
=3D Private->DelayedDispatchTable) {
 
+=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ZeroMem (Private->DelayedDispatchTa=
ble, TableSize);
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0 Status =3D PeiServicesInstallPpi (&mDelayedDispatchDesc);<=
o:p>
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ASSER=
T_EFI_ERROR (Status);
&=
nbsp;
+=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 Status =3D PeiServicesNotifyPpi (&mDelayedDispatchNo=
tifyDesc);
 =
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 ASSERT_EFI_ERROR (Status);
 
+=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 }
&n=
bsp;
+=C2=A0=C2=A0=C2=A0 }
 
+=C2=A0 }
 
+=
 
=C2=A0=C2=A0 if ((Private->PeiMemoryInstalled) &&<=
/o:p>
 
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (PcdGetBool (PcdM= igrateTemporaryRamFirmwareVolumes) ||
 
=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 (Private->HobList.HandoffInformationTa=
ble->BootMode !=3D
BOOT_O=
N_S3_RESUME) ||
 <=
/o:p>
@@ -1621,6 +1967,13 @@ PeiDispatc=
her (
=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }<=
/o:p>
 
+
=
 
+=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 // Dispatch pending delalyed dispatch requests
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (NULL !=3D =
Private->DelayedDispatchTable) {
 
+=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (DelayedDispatchDispatcher=
 (Private->DelayedDispatchTable,
NULL)) {
 =
;
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ProcessDispatchNotifyList (Private);
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 }
 
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 }
 
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }=
 
 
 
=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 //
&=
nbsp;
diff --git a/MdeModulePkg/C=
ore/Pei/PeiMain/PeiMain.c
b/=
MdeModulePkg/Core/Pei/PeiMain/PeiMain.c
index bf1719d7941a..e5643adf7027 100644
=
--- a/MdeModulePkg/Core/Pei/PeiMain/PeiMain.c<=
/o:p>
+++ b/MdeModulePkg/Core/Pei/PeiMa=
in/PeiMain.c
@@ -277,6 +277,=
9 @@ PeiCore (
=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 OldCoreData->TempFileHandles =3D (E=
FI_PEI_FILE_HANDLE
*)((UINT8=
 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
 
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
 
 
 <=
/o:p>
+=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /=
/ Force relocating the dispatch table
 
+=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 OldCoreData->DelayedDispatchTable =3D NULL;
 
+
&=
nbsp;
=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 //
 
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
 // Fixup for PeiService's address
 
=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0 //
=
 
diff --git a/MdeModul=
ePkg/Core/Pei/PeiMain.h
b/Md=
eModulePkg/Core/Pei/PeiMain.h
index 556beddad533..3b8bbe7f25a1 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.h
=
+++ b/MdeModulePkg/Core/Pei/PeiMain.h
@@ -11,6 +11,8 @@ SPDX-License-Identifier=
: BSD-2-Clause-Patent
&=
nbsp;
 
 #include <PiPei.h>
 
 #include <Ppi/DxeIpl.h>
 
+#include &l=
t;Ppi/DelayedDispatch.h>
=
 
+#include <Ppi/End=
OfPeiPhase.h>
 =
 #include <Ppi/MemoryDiscover=
ed.h>
 
 #include <Ppi/StatusCode.h><=
/o:p>
 
#include <Ppi/Reset.h>
<= pre> 
@@ -41,6 +43,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent=
 #include <IndustryStandard/PeImage=
.h>
 
 #include <Library/PeiServicesTablePoin=
terLib.h>
 
 #include <Library/MemoryAllocati=
onLib.h>
 
+#include <Library/TimerLib.h><=
o:p>
 
 #include <Guid/FirmwareFileSystem2.h>=
 
#include <Guid/FirmwareFileSystem3.h>
 
<=
span lang=3DEN-US> #include <Guid/AprioriFileName.h>
 
@@ -207,6 +210,29 @@ EFI_STATUS
 
&n=
bsp;
 #define PEI_CORE_HANDLE_SIG=
NATURE=C2=A0 SIGNATURE_32('P','e','i','C')
 
&=
nbsp;
 
+#define GET_TIME_IN_US()
((UINT32)DivU64x32(GetTimeInNanoSecond(GetPerforma=
nceCounter ()),
1000))<=
/o:p>
 
+
=
 
+//
 
+// Internal structure for delayed dispatch entries.<=
/pre>
 
+//
 
+#pragma pack (push, 1)
 
+
 <=
/o:p>
+typedef struct {
 
+=C2=A0 EFI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 UniqueId;
 
+=C2=A0 UINT64=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 Context;
 
+=C2=A0 EFI_DELAYED_DISPATCH_FUNCTIO=
N=C2=A0=C2=A0=C2=A0 Function;
 
+=C2=A0 UINT32=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 DispatchTime;
 =
;
+=C2=A0 UINT32=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Microsec=
ondDelay;
 <=
/span>
+} DELAYED_DISPATCH_ENTRY;
 
+
 <=
/o:p>
+typedef struct {
 
+=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Count;
 
+=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0DispCount;
 =
+=C2=A0 DELAYED_DISPATCH_ENTRY=
=C2=A0=C2=A0=C2=A0 Entry[1];=C2=A0=C2=A0=C2=A0=C2=A0 // Actual size based o=
n
PCD PcdDelayedDispatchMaxE=
ntries;
 
+} DELAYED_DISPATCH_TABLE;
 
+
 
+#pragma pack (pop)
 
+
 
 ///
 
 /// =
Pei Core private data structure instance
 
 ///
 
<= pre>@@ -307,6 +333,11 @@ struct _PEI_CORE_INSTANCE {
=C2=A0=C2=A0 // Those Memory Ra=
nge will be migrated into physical memory.
 
=C2=A0=
=C2=A0 //
 <=
/span>
=C2=A0=C2=A0 HOLE_MEMORY_DATA
HoleData[HOLE_MAX_NUMBER];=
 
+
 =
;
+=C2=A0 //
 
+=C2=A0 // Table of delayed dispatch requests
=
 
+=C2=A0 //
 
+=C2=A0 DELAYED_DISPATCH_TABLE=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *DelayedDis=
patchTable;
 
 };
 
&n=
bsp;
 
 ///
 
@@ -2038,4 +2069,4=
9 @@ PeiReinitializeFv (
=C2=
=A0=C2=A0 IN=C2=A0 PEI_CORE_INSTANCE=C2=A0 *PrivateData
 
=C2=A0=C2=A0 );
 
 =
 
+/**
 
+Register a callback to be called a=
fter a minimum delay has occurred.
 
+=
 
+This service is the single member function of the
EFI_DELAYED_DISPATCH_PPI<=
/span>
 
+
 =
+=C2=A0 @param[in] This=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Pointer to the EFI_DELA=
YED_DISPATCH_PPI
instance
 
=
+=C2=A0 @param[in] Function =C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0Function to call back
 
+=C2=A0 @par=
am[in] Context=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Context data<=
/o:p>
 
+=C2=A0 @param[in] UniqueId=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0 GUID for this Delayed Dispatch request.
 
+=C2=A0 @param[in] Delay=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0 Delay interval
&=
nbsp;
+
 
+=C2=A0 @retval EFI_SUCCESS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Function successfully loaded
 
+=C2=A0 @retval EFI_INVALID_PARAMETER=C2=A0=C2=A0=C2=A0= =C2=A0 One of the Arguments is not
supported
&nbs=
p;
+=C2=A0 @retval EFI_OUT_OF_RES=
OURCES=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 No more entries
 
+
 
+**/
 
+EFI_STATUS<=
o:p>
 
+EFIAPI
 
+PeiDelayedDisp=
atchRegister (
 
+=C2=A0 IN=C2=A0 EFI_DELAYED_DISPA=
TCH_PPI=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0*This,
<= pre> 
+=C2=A0 IN=C2=A0 EFI_DELAYED_DISPATCH_FUNCTION=C2=A0 Function,=
 
+=C2=A0 IN=C2=A0 UINT64=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 Context,
 
+=C2=
=A0 IN=C2=A0 EFI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 *UniqueId=C2=A0=C2=A0 OPTIONAL,
 
+=C2=A0 IN=
=C2=A0 UINT32=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 Delay
 <=
/o:p>
+=C2=A0 );
 
+
 
+/**
 
+=C2=A0 Wait=
 on a registered Delayed Dispatch unit that has a UniqueId.
Continue
 
+=C2=A0 =
to dispatch all registered delayed dispatch entries until *ALL* entries
with
<=
span lang=3DEN-US> 
+=
=C2=A0 UniqueId have completed.
 
+
 
+=C2=A0 @param[in]=C2=A0=C2=A0=C2=A0=C2=A0 This=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 The Delayed Dispatch PP=
I pointer.
 =
+=C2=A0 @param[in]=C2=A0=C2=A0=C2=A0=
=C2=A0 UniqueId=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 UniqueId of delay=
ed dispatch entry.
&nbs=
p;
+
=
 
+=
=C2=A0 @retval EFI_SUCCESS=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 The operation succeeds.
 
+=C2=
=A0 @retval EFI_INVALID_PARAMETER=C2=A0 The parameters are invalid.
 
=
+
&n=
bsp;
+**/
=
 
+EFI_STATUS
 
+EFIAPI
 
=
+PeiDelayedDispatchWaitOnUniqueId (
 
+=C2=A0 IN E=
FI_DELAYED_DISPATCH_PPI=C2=A0 *This,
 
+=C2=A0 IN E=
FI_GUID=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 *UniqueId
=
 
+=
=C2=A0 );
 <=
/span>
+
 
 #endif
 
<= pre>diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf<= /o:p>
b/MdeModulePkg/Core/Pei/PeiMain.i=
nf
index 0cf357371a16..73738=
c939ac7 100644
--- a/MdeModu=
lePkg/Core/Pei/PeiMain.inf
+=
++ b/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -66,6 +66,7 @@ [LibraryClasses]
<=
span lang=3DEN-US>=C2=A0=C2=A0 PeCoffLib
 
=C2=A0=
=C2=A0 PeiServicesTablePointerLib
 
=C2=A0=C2=A0 Pc=
dLib
 
+=C2=A0 TimerLib
 
<=
o:p> 
 
 [Guids]
 
=C2=A0=
=C2=A0 gPeiAprioriFileNameGuid=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ## SOMET=
IMES_CONSUMES=C2=A0=C2=A0 ## File
 
@@ -78,6 +79,7 =
@@ [Guids]
=C2=A0=C2=A0 gEfi=
FirmwareFileSystem3Guid
 
=C2=A0=C2=A0 gStatusCodeC=
allbackGuid
 
=C2=A0=C2=A0 gEdkiiMigratedFvInfoGuid=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ##
SOMETIMES_PRODUCES=C2=A0=C2=A0=C2=A0=C2=A0 ## HO=
B
 
+=C2=A0 gEfiDelayedDispatchTableGuid=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 ##
SOMETI=
MES_PRODUCES=C2=A0=C2=A0=C2=A0=C2=A0 ## HOB
 
=
 
 
 [Ppis]
 
=C2=A0=C2=A0=
 gEfiPeiStatusCodePpiGuid=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0 ##
SOMETIMES_CONSUMES # =
PeiReportStatusService is not ready if this PPI
doesn't exist
 
@@ -100,6 +102,=
8 @@ [Ppis]
=C2=A0=C2=A0 gEf=
iPeiReset2PpiGuid=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0 ##
SOMETI=
MES_CONSUMES
 
=C2=A0=C2=A0 gEfiSecHobDataPpiGuid=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ##
SOMETIMES_CONSUMES<=
/span>
 
=C2=A0=C2=A0 gEfiPeiCoreFvLocationPpiGuid=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0 ##
SOMETIMES_CONSU=
MES
 =
+=C2=A0 gEfiPeiDelayedDispatchPpiGuid=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0 ##
SOMETIMES=
_CONSUMES
 <=
/span>
[Liming] Here should PRODU=
CES. 
 
+=C2=A0 gEfiEndOfPeiSignalPpiGuid=C2=A0=C2=A0=C2=A0=C2=A0=
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 ## CONSUMES
 
 
 
<=
span lang=3DEN-US> [Pcd]
 
=C2=A0=C2=A0 gEfiMdeModu=
lePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize
<=
span lang=3DEN-US>## CONSUMES
 
@@ -112,6 +116,9 @@=
 [Pcd]
=C2=A0=C2=A0 gEfiMdeM=
odulePkgTokenSpaceGuid.PcdShadowPeimOnBoot
## CONSUMES
<=
o:p> 
=C2=A0=C2=A0 gEfiMdeMo=
dulePkgTokenSpaceGuid.PcdInitValueInTempStack
<=
span lang=3DEN-US>## CONSUMES
 
 
gEfiMdeModulePkgTokenSpaceGuid.PcdMigrat=
eTemporaryRamFirmwareVolu
me=
s=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ## CONSUMES
 
+=C2=
=A0 gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs<=
/span>
## CONSUMES
 
+=
gEfiMdeModulePkgTokenSpaceG=
uid.PcdDelayedDispatchCompletionTimeout
Us=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ## CONSUMES<=
/pre>
 
+=C2=A0 gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxEntrie=
s
## CONSUMES
 
 
&nbs=
p;
 # [BootMode]
 
 # S3_RESUME=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 ## SOMETIMES_CONSUMES
 
diff =
--git a/MdeModulePkg/MdeModulePkg.dec
b/MdeModulePkg/MdeModulePkg.dec
index 0ff058b0a9da..2f4bd2f2b773 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec<=
/o:p>
@@ -418,6 +418,9 @@ [Guids]<=
/o:p>
=C2=A0=C2=A0 ## Include/Guid/Migr=
atedFvInfo.h
 
=C2=A0=C2=A0 gEdkiiMigratedFvInfoGui=
d =3D { 0xc1ab12f7, 0x74aa, 0x408d, { 0xa2, 0xf4,
0xc6, 0xce, 0xfd, 0x17, 0x98, 0x71 } }
 
 
&nbs=
p;
+=C2=A0 ## Delayed Dispatch ta=
ble GUID
 
+=C2=A0 gEfiDelayedDispatchTableGuid =3D=
 { 0x4b733449, 0x8eff, 0x488c, {0x92,
0x1a, 0x15, 0x4a, 0xda, 0x25, 0x18, 0x07}}
 
+
[Liming] =
This GUID is only used in PeiMain. I suggest to define the global
GUID variable in PeiCore for this usa=
ge.
 =
 
=C2=A0=
=C2=A0 #
 
=C2=A0=C2=A0 # GUID defined in Universal=
Payload
 
=C2=A0=C2=A0 #
 
=
@@ -991,6 +994,18 @@ [PcdsFixedAtBuild]
=C2=A0=C2=A0 # @ValidList=C2=A0 0x80000006 | 0x03058002
 
=
 
gE=
fiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|U
INT32|0x30001040
 
 
 
+=C2=A0 ## Delayed Dispatch Maximum =
Delay in us (microseconds)
<=
o:p> 
+=C2=A0 # Maximum dela=
y for any particular delay request - 5 seconds
=
 
+<=
o:p>
gEfiMdeModulePkgTokenSpaceGu=
id.PcdDelayedDispatchMaxDelayUs|500000
0|UINT32|0x3000104A
 
+
 
+=C2=A0 ## Delayed Dispatch timeout in us (microseconds)
 
<=
span lang=3DEN-US>+=C2=A0 # Maximum delay when waiting for completion (ie E=
ndOfPei) - 10 seconds
&=
nbsp;
+
gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchComp= letionTimeout
Us|10000000|UI=
NT32|0x3000104B
 <=
/o:p>
+
 
+=C2=
=A0 ## Delayed Dispatch Max Entries
 
+=C2=A0 # Ma=
ximum number of delayed dispatch entries
 
+
gEfiMdeModulePkgTokenSpaceGuid.Pcd=
DelayedDispatchMaxEntries|8|UINT3
2|0x3000104C
&nbs=
p;
+
[Liming] I suggest to define MACRO in PeiCo=
re for them. If there is real
usage model, new PCD can be introduced later. 
 
=
Thanks
Liming
 
=C2=
=A0=C2=A0 ## Mask to control the NULL address detection in code for differe=
nt
phases.=
 
=C2=A0=C2=A0 #=C2=A0 If enabled, accessing NULL address in UEFI or=
 SMM code can be
caught.<=
BR><BR>
 =
=C2=A0=C2=A0 #=C2=A0=C2=A0=C2=A0=
 BIT0=C2=A0=C2=A0=C2=A0 - Enable NULL pointer detection for UEFI.<BR>=
 
--
2.41.0.windows.2
 
 =
 
 
=
 
 
 
 

_._,_._,_

Groups.io Links:

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

View/Reply Online (#107447) | =20 | Mute= This Topic | New Topic
Your Subscriptio= n | Contact Group Owner | Unsubscribe [importer@patchew.org]

_._,_._,_
------=_NextPart_000_003D_01D9C543.6BFD8DC0--