public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8
@ 2023-10-10  0:18 Kun Qin
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 1/4] MdePkg: DelayedDispatch: Correct PPI descriptions Kun Qin
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Kun Qin @ 2023-10-10  0:18 UTC (permalink / raw)
  To: devel
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Jian J Wang,
	Dandan Bi, Debkumar De, Catharine West

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496

This patch series is a follow-up of previous submission:
https://edk2.groups.io/g/devel/message/107111

The main changes between v1 and v2 patches are:
  - Fixed function documentation
  - Removed GUID declaration internal to PEI core
  - Removed max entry PCD declaration and use macro instead

Patch branch: https://github.com/kuqin12/edk2/tree/Delayed_Dispatch_v3

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Debkumar De <debkumar.de@intel.com>
Cc: Catharine West <catharine.west@intel.com>

Kun Qin (4):
  MdePkg: DelayedDispatch: Correct PPI descriptions
  MdePkg: DelayedDispatch: Added WaitOnEvent interface
  MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch
  MdeModulePkg: PeiMain: Updated dispatcher for delayed dispatch

 MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 371 +++++++++++++++++++-
 MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |   3 +
 MdeModulePkg/Core/Pei/PeiMain.h               |  76 ++++
 MdeModulePkg/Core/Pei/PeiMain.inf             |   5 +
 MdeModulePkg/MdeModulePkg.dec                 |   8 +
 MdePkg/Include/Ppi/DelayedDispatch.h          |  41 ++-
 6 files changed, 494 insertions(+), 10 deletions(-)

-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109466): https://edk2.groups.io/g/devel/message/109466
Mute This Topic: https://groups.io/mt/101865807/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH v2 1/4] MdePkg: DelayedDispatch: Correct PPI descriptions
  2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
@ 2023-10-10  0:18 ` Kun Qin
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface Kun Qin
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Kun Qin @ 2023-10-10  0:18 UTC (permalink / raw)
  To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Mike Turner

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496

PI spec defined the `Register` function input argument `Delay` as output.
However, this parameter should be used to define the minmal time delay
the callback should fire. Thus it should be an input parameter.

This change fixed the argument type.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>

Co-authored-by: Mike Turner <mikeyt@pobox.com>
Signed-off-by: Kun Qin <kuqin12@gmail.com>
---

Notes:
    v2:
    - No review, no change.

 MdePkg/Include/Ppi/DelayedDispatch.h | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/MdePkg/Include/Ppi/DelayedDispatch.h b/MdePkg/Include/Ppi/DelayedDispatch.h
index f9b4fed30fb0..098d57758551 100644
--- a/MdePkg/Include/Ppi/DelayedDispatch.h
+++ b/MdePkg/Include/Ppi/DelayedDispatch.h
@@ -4,6 +4,7 @@
     Provide timed event service in PEI
 
     Copyright (c) 2020, American Megatrends International LLC. All rights reserved.
+    Copyright (c) Microsoft Corporation.
     SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
@@ -15,7 +16,7 @@
 ///
 #define EFI_DELAYED_DISPATCH_PPI_GUID \
   { \
-    0x869c711d, 0x649c, 0x44fe, { 0x8b, 0x9e, 0x2c, 0xbb, 0x29, 0x11, 0xc3, 0xe6} } \
+    0x869c711d, 0x649c, 0x44fe, { 0x8b, 0x9e, 0x2c, 0xbb, 0x29, 0x11, 0xc3, 0xe6} \
   }
 
 /**
@@ -46,10 +47,10 @@ Register a callback to be called after a minimum delay has occurred.
 
 This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
 
-  @param This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
-  @param Function       Function to call back
-  @param Context        Context data
-  @param Delay          Delay interval
+  @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
+  @param[in] Function       Function to call back
+  @param[in] Context        Context data
+  @param[in] Delay          Delay interval
 
   @retval EFI_SUCCESS               Function successfully loaded
   @retval EFI_INVALID_PARAMETER     One of the Arguments is not supported
@@ -61,8 +62,8 @@ EFI_STATUS
 (EFIAPI *EFI_DELAYED_DISPATCH_REGISTER)(
   IN  EFI_DELAYED_DISPATCH_PPI      *This,
   IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
-  IN  UINT64                     Context,
-  OUT UINT32                     Delay
+  IN  UINT64                         Context,
+  IN  UINT32                         Delay
   );
 
 ///
-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109467): https://edk2.groups.io/g/devel/message/109467
Mute This Topic: https://groups.io/mt/101865808/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface
  2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 1/4] MdePkg: DelayedDispatch: Correct PPI descriptions Kun Qin
@ 2023-10-10  0:18 ` Kun Qin
  2023-10-10  8:46   ` Laszlo Ersek
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch Kun Qin
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Kun Qin @ 2023-10-10  0:18 UTC (permalink / raw)
  To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Mike Turner

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496

This change adds a new interface for the delayed dispatch PPI. This
new addition allows functional components relying on delayed dispatch
callbacks to be managed/dispatched with definitive order.

The full defintion has been added into PI spec.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>

Co-authored-by: Mike Turner <mikeyt@pobox.com>
Signed-off-by: Kun Qin <kuqin12@gmail.com>
---

Notes:
    v2:
    - Fixed PI spec version number to v1.8 [Liming]

 MdePkg/Include/Ppi/DelayedDispatch.h | 26 ++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/MdePkg/Include/Ppi/DelayedDispatch.h b/MdePkg/Include/Ppi/DelayedDispatch.h
index 098d57758551..0efcfdbfced6 100644
--- a/MdePkg/Include/Ppi/DelayedDispatch.h
+++ b/MdePkg/Include/Ppi/DelayedDispatch.h
@@ -1,5 +1,5 @@
 /** @file
-    EFI Delayed Dispatch PPI as defined in the PI 1.7 Specification
+    EFI Delayed Dispatch PPI as defined in the PI 1.8 Specification
 
     Provide timed event service in PEI
 
@@ -50,6 +50,7 @@ This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
   @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
   @param[in] Function       Function to call back
   @param[in] Context        Context data
+  @param[in] UniqueId       GUID for this Delayed Dispatch request.
   @param[in] Delay          Delay interval
 
   @retval EFI_SUCCESS               Function successfully loaded
@@ -63,9 +64,29 @@ EFI_STATUS
   IN  EFI_DELAYED_DISPATCH_PPI      *This,
   IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
   IN  UINT64                         Context,
+  IN  EFI_GUID                      *UniqueId   OPTIONAL,
   IN  UINT32                         Delay
   );
 
+/**
+  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
+  to dispatch all registered delayed dispatch entries until *ALL* entries with
+  UniqueId have completed.
+
+  @param[in]     This            The Delayed Dispatch PPI pointer.
+  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
+
+  @retval EFI_SUCCESS            The operation succeeds.
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_DELAYED_DISPATCH_WAIT_ON_EVENT)(
+  IN  EFI_DELAYED_DISPATCH_PPI      *This,
+  IN  EFI_GUID                      *UniqueId
+  );
+
 ///
 /// This PPI is a pointer to the Delayed Dispatch Service.
 /// This service will be published by the Pei Foundation. The PEI Foundation
@@ -73,7 +94,8 @@ EFI_STATUS
 /// execution.
 ///
 struct _EFI_DELAYED_DISPATCH_PPI {
-  EFI_DELAYED_DISPATCH_REGISTER    Register;
+  EFI_DELAYED_DISPATCH_REGISTER         Register;
+  EFI_DELAYED_DISPATCH_WAIT_ON_EVENT    WaitOnEvent;
 };
 
 extern EFI_GUID  gEfiPeiDelayedDispatchPpiGuid;
-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109468): https://edk2.groups.io/g/devel/message/109468
Mute This Topic: https://groups.io/mt/101865809/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch
  2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 1/4] MdePkg: DelayedDispatch: Correct PPI descriptions Kun Qin
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface Kun Qin
@ 2023-10-10  0:18 ` Kun Qin
  2023-10-10 13:14   ` Laszlo Ersek
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 4/4] MdeModulePkg: PeiMain: Updated dispatcher for " Kun Qin
  2023-10-11  1:48 ` 回复: [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 gaoliming via groups.io
  4 siblings, 1 reply; 8+ messages in thread
From: Kun Qin @ 2023-10-10  0:18 UTC (permalink / raw)
  To: devel
  Cc: Jian J Wang, Dandan Bi, Liming Gao, Debkumar De, Catharine West,
	Mike Turner

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496

This change adds the implementation 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.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
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@gmail.com>
---

Notes:
    v2:
    - Fixed function documentation [Liming]
    - Removed GUID declaration internal to PEI core [Liming]
    - Removed max entry PCD declaration and use macro instead [Liming]
    - Added "PRODUCED" in inf [Liming]

 MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 366 ++++++++++++++++++++
 MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |   3 +
 MdeModulePkg/Core/Pei/PeiMain.h               |  76 ++++
 MdeModulePkg/Core/Pei/PeiMain.inf             |   5 +
 MdeModulePkg/MdeModulePkg.dec                 |   8 +
 5 files changed, 458 insertions(+)

diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index 5f32ebb560ae..f7f4cce84174 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -3,14 +3,354 @@
 
 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+Copyright (c) Microsoft Corporation.
 SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
 #include "PeiMain.h"
 
+//
+// Maximal number of Delayed Dispatch entries supported
+//
+#define DELAYED_DISPATCH_MAX_ENTRIES  8
+
+//
+// Utility global variables
+//
+
+// Delayed Dispatch table GUID
+EFI_GUID  gEfiDelayedDispatchTableGuid = {
+  0x4b733449, 0x8eff, 0x488c, { 0x92, 0x1a, 0x15, 0x4a, 0xda, 0x25, 0x18, 0x07 }
+};
+
+/**
+  DelayedDispatchDispatcher
+
+  ayed Dispach cycle (ie one pass) through each entry, calling functions when their
+  e has expired.  When UniqueId is specified, if there are any of the specified entries
+  the dispatch queue during dispatch, repeat the DelayedDispatch cycle.
+
+  @param DelayedDispatchTable  Pointer to dispatch table
+  @param OPTIONAL              UniqueId used to insure particular time is met.
+
+  @return BOOLEAN
+**/
+BOOLEAN
+DelayedDispatchDispatcher (
+  IN DELAYED_DISPATCH_TABLE  *DelayedDispatchTable,
+  IN EFI_GUID                *UniqueId           OPTIONAL
+  );
+
+/**
+  DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch
+  entries are complete before exiting PEI.
+
+  @param[in] PeiServices   - Pointer to PEI Services Table.
+  @param[in] NotifyDesc    - Pointer to the descriptor for the Notification event that
+                             caused this function to execute.
+  @param[in] Ppi           - Pointer to the PPI data associated with this function.
+
+  @retval EFI_STATUS       - Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchOnEndOfPei (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,
+  IN VOID                       *Ppi
+  );
+
+EFI_DELAYED_DISPATCH_PPI  mDelayedDispatchPpi  = { PeiDelayedDispatchRegister, PeiDelayedDispatchWaitOnUniqueId };
+EFI_PEI_PPI_DESCRIPTOR    mDelayedDispatchDesc = {
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+  &gEfiPeiDelayedDispatchPpiGuid,
+  &mDelayedDispatchPpi
+};
+
+EFI_PEI_NOTIFY_DESCRIPTOR  mDelayedDispatchNotifyDesc = {
+  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+  &gEfiEndOfPeiSignalPpiGuid,
+  PeiDelayedDispatchOnEndOfPei
+};
+
+/**
+  Helper function to look up DELAYED_DISPATCH_TABLE published in HOB.
+
+  @return Pointer to DELAYED_DISPATCH_TABLE from HOB
+**/
+DELAYED_DISPATCH_TABLE *
+GetDelayedDispatchTable (
+  VOID
+  )
+{
+  EFI_HOB_GUID_TYPE  *GuidHob;
+
+  GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
+  if (NULL == GuidHob) {
+    DEBUG ((DEBUG_ERROR, "Delayed Dispatch PPI ERROR - Delayed Dispatch Hob not available.\n"));
+    ASSERT (FALSE);
+    return NULL;
+  }
+
+  return (DELAYED_DISPATCH_TABLE *)GET_GUID_HOB_DATA (GuidHob);
+}
+
+/**
+  Register a callback to be called after a minimum delay has occurred.
+
+  This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
+
+  @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
+  @param[in] Function       Function to call back
+  @param[in] Context        Context data
+  @param[in] UniqueId       GUID for this Delayed Dispatch request.
+  @param[in] Delay          Delay interval
+
+  @retval EFI_SUCCESS               Function successfully loaded
+  @retval EFI_INVALID_PARAMETER     One of the Arguments is not supported
+  @retval EFI_OUT_OF_RESOURCES      No more entries
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchRegister (
+  IN  EFI_DELAYED_DISPATCH_PPI       *This,
+  IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
+  IN  UINT64                         Context,
+  IN  EFI_GUID                       *UniqueId   OPTIONAL,
+  IN  UINT32                         Delay
+  )
+{
+  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
+  DELAYED_DISPATCH_ENTRY  *Entry;
+
+  // Check input parameters
+  if ((NULL == Function) || (Delay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) || (NULL == This)) {
+    DEBUG ((DEBUG_ERROR, "%a Invalid parameter\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get delayed dispatch table
+  DelayedDispatchTable = GetDelayedDispatchTable ();
+  if (NULL == DelayedDispatchTable) {
+    DEBUG ((DEBUG_ERROR, "%a Unable to locate dispatch table\n", __func__));
+    return EFI_UNSUPPORTED;
+  }
+
+  // Check for available entry slots
+  if (DelayedDispatchTable->Count >= DELAYED_DISPATCH_MAX_ENTRIES) {
+    ASSERT (DelayedDispatchTable->Count < DELAYED_DISPATCH_MAX_ENTRIES);
+    DEBUG ((DEBUG_ERROR, "%a Too many entries requested\n", __func__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Entry               = &(DelayedDispatchTable->Entry[DelayedDispatchTable->Count]);
+  Entry->Function     = Function;
+  Entry->Context      = Context;
+  Entry->DispatchTime = GET_TIME_IN_US () + Delay;
+  if (NULL != UniqueId) {
+    CopyGuid (&Entry->UniqueId, UniqueId);
+  } else {
+    ZeroMem (&Entry->UniqueId, sizeof (EFI_GUID));
+  }
+
+  Entry->MicrosecondDelay = Delay;
+  DelayedDispatchTable->Count++;
+
+  DEBUG ((DEBUG_INFO, "%a  Adding dispatch Entry\n", __func__));
+  DEBUG ((DEBUG_INFO, "    Requested Delay = %d\n", Delay));
+  DEBUG ((DEBUG_INFO, "    Trigger Time = %d\n", Entry->DispatchTime));
+  DEBUG ((DEBUG_INFO, "    Context = 0x%08lx\n", Entry->Context));
+  DEBUG ((DEBUG_INFO, "    Function = %p\n", Entry->Function));
+  DEBUG ((DEBUG_INFO, "    GuidHandle = %g\n", &(Entry->UniqueId)));
+
+  if (0 == Delay) {
+    // Force early dispatch point
+    DelayedDispatchDispatcher (DelayedDispatchTable, NULL);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  DelayedDispatchDispatcher
+
+  Delayed Dispach cycle (ie one pass) through each entry, calling functions when their
+  time has expired.  When UniqueId is specified, if there are any of the specified entries
+  in the dispatch queue during dispatch, repeat the DelayedDispatch cycle.
+
+  @param DelayedDispatchTable  Pointer to dispatch table
+  @param OPTIONAL              UniqueId used to insure particular time is met.
+
+  @return BOOLEAN
+**/
+BOOLEAN
+DelayedDispatchDispatcher (
+  IN DELAYED_DISPATCH_TABLE  *DelayedDispatchTable,
+  IN EFI_GUID                *UniqueId           OPTIONAL
+  )
+{
+  BOOLEAN                 Dispatched;
+  UINT32                  TimeCurrent;
+  UINT32                  MaxDispatchTime;
+  UINTN                   Index1;
+  BOOLEAN                 UniqueIdPresent;
+  DELAYED_DISPATCH_ENTRY  *Entry;
+
+  Dispatched      = FALSE;
+  UniqueIdPresent = TRUE;
+  MaxDispatchTime = GET_TIME_IN_US () + FixedPcdGet32 (PcdDelayedDispatchCompletionTimeoutUs);
+  while ((DelayedDispatchTable->Count > 0) && (UniqueIdPresent)) {
+    UniqueIdPresent = FALSE;
+    DelayedDispatchTable->DispCount++;
+
+    // If dispatching is messed up, clear DelayedDispatchTable and exit.
+    TimeCurrent =  GET_TIME_IN_US ();
+    if (TimeCurrent > MaxDispatchTime) {
+      DEBUG ((DEBUG_ERROR, "%a - DelayedDispatch Completion timeout!\n", __func__));
+      ReportStatusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE), (EFI_SOFTWARE_PEI_CORE | EFI_SW_EC_ABORTED));
+      ASSERT (FALSE);
+      DelayedDispatchTable->Count = 0;
+      break;
+    }
+
+    // Check each entry in the table for possible dispatch
+    for (Index1 = 0; Index1 < DelayedDispatchTable->Count;) {
+      Entry = &(DelayedDispatchTable->Entry[Index1]);
+      // If UniqueId is present, insure there is an additional check of the table.
+      if (NULL != UniqueId) {
+        if (CompareGuid (UniqueId, &Entry->UniqueId)) {
+          UniqueIdPresent = TRUE;
+        }
+      }
+
+      TimeCurrent =  GET_TIME_IN_US ();
+      if (TimeCurrent >= Entry->DispatchTime) {
+        // Time expired, invoked the function
+        DEBUG ((
+          DEBUG_ERROR,
+          "Delayed dispatch entry %d @ %p, Target=%d, Act=%d Disp=%d\n",
+          Index1,
+          Entry->Function,
+          Entry->DispatchTime,
+          TimeCurrent,
+          DelayedDispatchTable->DispCount
+          ));
+        Dispatched              = TRUE;
+        Entry->MicrosecondDelay = 0;
+        Entry->Function (
+                 &Entry->Context,
+                 &Entry->MicrosecondDelay
+                 );
+        DEBUG ((DEBUG_ERROR, "Delayed dispatch Function returned delay=%d\n", Entry->MicrosecondDelay));
+        if (0 == Entry->MicrosecondDelay) {
+          // NewTime = 0 = delete this entry from the table
+          DelayedDispatchTable->Count--;
+          CopyMem (Entry, Entry+1, sizeof (DELAYED_DISPATCH_ENTRY) * (DelayedDispatchTable->Count - Index1));
+        } else {
+          if (Entry->MicrosecondDelay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) {
+            DEBUG ((DEBUG_ERROR, "%a Illegal new delay %d requested\n", __func__, Entry->MicrosecondDelay));
+            ASSERT (FALSE);
+            Entry->MicrosecondDelay = FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs);
+          }
+
+          // NewTime != 0 - update the time from us to Dispatch time
+          Entry->DispatchTime =  GET_TIME_IN_US () + Entry->MicrosecondDelay;
+          Index1++;
+        }
+      } else {
+        Index1++;
+      }
+    }
+  }
+
+  return Dispatched;
+}
+
+/**
+  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
+  to dispatch all registered delayed dispatch entries until *ALL* entries with
+  UniqueId have completed.
+
+  @param[in]     This            The Delayed Dispatch PPI pointer.
+  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
+
+  @retval EFI_SUCCESS            The operation succeeds.
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchWaitOnUniqueId (
+  IN EFI_DELAYED_DISPATCH_PPI  *This,
+  IN EFI_GUID                  *UniqueId
+  )
+{
+  PERF_FUNCTION_BEGIN ();
+  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
+
+  // Get delayed dispatch table
+  DelayedDispatchTable = GetDelayedDispatchTable ();
+  if (NULL == DelayedDispatchTable) {
+    PERF_FUNCTION_END ();
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((NULL == UniqueId) || (IsZeroGuid (UniqueId))) {
+    ASSERT (FALSE);
+    PERF_FUNCTION_END ();
+    return EFI_UNSUPPORTED;
+  }
+
+  DEBUG ((DEBUG_INFO, "Delayed dispatch on %g. Count=%d, DispatchCount=%d\n", UniqueId, DelayedDispatchTable->Count, DelayedDispatchTable->DispCount));
+  PERF_EVENT_SIGNAL_BEGIN (UniqueId);
+  DelayedDispatchDispatcher (DelayedDispatchTable, UniqueId);
+  PERF_EVENT_SIGNAL_END (UniqueId);
+
+  PERF_FUNCTION_END ();
+  return EFI_SUCCESS;
+}
+
 /**
+  DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch
+  entries are complete before exiting PEI.
 
+  @param[in] PeiServices   - Pointer to PEI Services Table.
+  @param[in] NotifyDesc    - Pointer to the descriptor for the Notification event that
+                             caused this function to execute.
+  @param[in] Ppi           - Pointer to the PPI data associated with this function.
+
+  @retval EFI_STATUS       - Always return EFI_SUCCESS
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchOnEndOfPei (
+  IN EFI_PEI_SERVICES           **PeiServices,
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,
+  IN VOID                       *Ppi
+  )
+{
+  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
+
+  // Get delayed dispatch table
+  DelayedDispatchTable = GetDelayedDispatchTable ();
+  if (NULL == DelayedDispatchTable) {
+    return EFI_UNSUPPORTED;
+  }
+
+  PERF_INMODULE_BEGIN ("PerfDelayedDispatchEndOfPei");
+  while (DelayedDispatchTable->Count > 0) {
+    DelayedDispatchDispatcher (DelayedDispatchTable, NULL);
+  }
+
+  DEBUG ((DEBUG_ERROR, "%a Count of dispatch cycles is %d\n", __func__, DelayedDispatchTable->DispCount));
+  PERF_INMODULE_END ("PerfDelayedDispatchEndOfPei");
+
+  return EFI_SUCCESS;
+}
+
+/**
   Discover all PEIMs and optional Apriori file in one FV. There is at most one
   Apriori file in one FV.
 
@@ -1365,12 +1705,31 @@ PeiDispatcher (
   EFI_PEI_FILE_HANDLE     SaveCurrentFileHandle;
   EFI_FV_FILE_INFO        FvFileInfo;
   PEI_CORE_FV_HANDLE      *CoreFvHandle;
+  EFI_HOB_GUID_TYPE       *GuidHob;
+  UINT32                  TableSize;
 
   PeiServices    = (CONST EFI_PEI_SERVICES **)&Private->Ps;
   PeimEntryPoint = NULL;
   PeimFileHandle = NULL;
   EntryPoint     = 0;
 
+  if (NULL == Private->DelayedDispatchTable) {
+    GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
+    if (NULL != GuidHob) {
+      Private->DelayedDispatchTable = (DELAYED_DISPATCH_TABLE *)(GET_GUID_HOB_DATA (GuidHob));
+    } else {
+      TableSize                     = sizeof (DELAYED_DISPATCH_TABLE) + ((DELAYED_DISPATCH_MAX_ENTRIES - 1) * sizeof (DELAYED_DISPATCH_ENTRY));
+      Private->DelayedDispatchTable = BuildGuidHob (&gEfiDelayedDispatchTableGuid, TableSize);
+      if (NULL != Private->DelayedDispatchTable) {
+        ZeroMem (Private->DelayedDispatchTable, TableSize);
+        Status = PeiServicesInstallPpi (&mDelayedDispatchDesc);
+        ASSERT_EFI_ERROR (Status);
+        Status = PeiServicesNotifyPpi (&mDelayedDispatchNotifyDesc);
+        ASSERT_EFI_ERROR (Status);
+      }
+    }
+  }
+
   if ((Private->PeiMemoryInstalled) &&
       (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
        (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||
@@ -1621,6 +1980,13 @@ PeiDispatcher (
             }
           }
         }
+
+        // Dispatch pending delalyed dispatch requests
+        if (NULL != Private->DelayedDispatchTable) {
+          if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
+            ProcessDispatchNotifyList (Private);
+          }
+        }
       }
 
       //
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 = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
       }
 
+      // Force relocating the dispatch table
+      OldCoreData->DelayedDispatchTable = NULL;
+
       //
       // Fixup for PeiService's address
       //
diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h
index 556beddad533..542b680c099c 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.h
+++ b/MdeModulePkg/Core/Pei/PeiMain.h
@@ -11,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #include <PiPei.h>
 #include <Ppi/DxeIpl.h>
+#include <Ppi/DelayedDispatch.h>
+#include <Ppi/EndOfPeiPhase.h>
 #include <Ppi/MemoryDiscovered.h>
 #include <Ppi/StatusCode.h>
 #include <Ppi/Reset.h>
@@ -41,6 +43,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <IndustryStandard/PeImage.h>
 #include <Library/PeiServicesTablePointerLib.h>
 #include <Library/MemoryAllocationLib.h>
+#include <Library/TimerLib.h>
 #include <Guid/FirmwareFileSystem2.h>
 #include <Guid/FirmwareFileSystem3.h>
 #include <Guid/AprioriFileName.h>
@@ -207,6 +210,29 @@ EFI_STATUS
 
 #define PEI_CORE_HANDLE_SIGNATURE  SIGNATURE_32('P','e','i','C')
 
+#define GET_TIME_IN_US()  ((UINT32)DivU64x32(GetTimeInNanoSecond(GetPerformanceCounter ()), 1000))
+
+//
+// Internal structure for delayed dispatch entries.
+//
+#pragma pack (push, 1)
+
+typedef struct {
+  EFI_GUID                         UniqueId;
+  UINT64                           Context;
+  EFI_DELAYED_DISPATCH_FUNCTION    Function;
+  UINT32                           DispatchTime;
+  UINT32                           MicrosecondDelay;
+} DELAYED_DISPATCH_ENTRY;
+
+typedef struct {
+  UINT32                    Count;
+  UINT32                    DispCount;
+  DELAYED_DISPATCH_ENTRY    Entry[1];     // Actual size based on usage, and cannot exceed DELAYED_DISPATCH_MAX_ENTRIES;
+} DELAYED_DISPATCH_TABLE;
+
+#pragma pack (pop)
+
 ///
 /// Pei Core private data structure instance
 ///
@@ -307,6 +333,11 @@ struct _PEI_CORE_INSTANCE {
   // Those Memory Range will be migrated into physical memory.
   //
   HOLE_MEMORY_DATA                  HoleData[HOLE_MAX_NUMBER];
+
+  //
+  // Table of delayed dispatch requests
+  //
+  DELAYED_DISPATCH_TABLE            *DelayedDispatchTable;
 };
 
 ///
@@ -2038,4 +2069,49 @@ PeiReinitializeFv (
   IN  PEI_CORE_INSTANCE  *PrivateData
   );
 
+/**
+Register a callback to be called after a minimum delay has occurred.
+
+This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
+
+  @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
+  @param[in] Function       Function to call back
+  @param[in] Context        Context data
+  @param[in] UniqueId       GUID for this Delayed Dispatch request.
+  @param[in] Delay          Delay interval
+
+  @retval EFI_SUCCESS               Function successfully loaded
+  @retval EFI_INVALID_PARAMETER     One of the Arguments is not supported
+  @retval EFI_OUT_OF_RESOURCES      No more entries
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchRegister (
+  IN  EFI_DELAYED_DISPATCH_PPI       *This,
+  IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
+  IN  UINT64                         Context,
+  IN  EFI_GUID                       *UniqueId   OPTIONAL,
+  IN  UINT32                         Delay
+  );
+
+/**
+  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
+  to dispatch all registered delayed dispatch entries until *ALL* entries with
+  UniqueId have completed.
+
+  @param[in]     This            The Delayed Dispatch PPI pointer.
+  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
+
+  @retval EFI_SUCCESS            The operation succeeds.
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiDelayedDispatchWaitOnUniqueId (
+  IN EFI_DELAYED_DISPATCH_PPI  *This,
+  IN EFI_GUID                  *UniqueId
+  );
+
 #endif
diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf
index 0cf357371a16..b2c1e53949de 100644
--- a/MdeModulePkg/Core/Pei/PeiMain.inf
+++ b/MdeModulePkg/Core/Pei/PeiMain.inf
@@ -66,6 +66,7 @@ [LibraryClasses]
   PeCoffLib
   PeiServicesTablePointerLib
   PcdLib
+  TimerLib
 
 [Guids]
   gPeiAprioriFileNameGuid       ## SOMETIMES_CONSUMES   ## File
@@ -100,6 +101,8 @@ [Ppis]
   gEfiPeiReset2PpiGuid                          ## SOMETIMES_CONSUMES
   gEfiSecHobDataPpiGuid                         ## SOMETIMES_CONSUMES
   gEfiPeiCoreFvLocationPpiGuid                  ## SOMETIMES_CONSUMES
+  gEfiPeiDelayedDispatchPpiGuid                 ## PRODUCES
+  gEfiEndOfPeiSignalPpiGuid                     ## CONSUMES
 
 [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize                  ## CONSUMES
@@ -112,6 +115,8 @@ [Pcd]
   gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot                        ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack                    ## CONSUMES
   gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolumes      ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeoutUs      ## CONSUMES
 
 # [BootMode]
 # S3_RESUME             ## SOMETIMES_CONSUMES
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index dd182c02fdf6..cb49ef50b864 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -994,6 +994,14 @@ [PcdsFixedAtBuild]
   # @ValidList  0x80000006 | 0x03058002
   gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|UINT32|0x30001040
 
+  ## Delayed Dispatch Maximum Delay in us (microseconds)
+  # Maximum delay for any particular delay request - 5 seconds
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs|5000000|UINT32|0x3000104A
+
+  ## Delayed Dispatch timeout in us (microseconds)
+  # Maximum delay when waiting for completion (ie EndOfPei) - 10 seconds
+  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeoutUs|10000000|UINT32|0x3000104B
+
   ## Mask to control the NULL address detection in code for different phases.
   #  If enabled, accessing NULL address in UEFI or SMM code can be caught.<BR><BR>
   #    BIT0    - Enable NULL pointer detection for UEFI.<BR>
-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109469): https://edk2.groups.io/g/devel/message/109469
Mute This Topic: https://groups.io/mt/101865810/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [edk2-devel] [PATCH v2 4/4] MdeModulePkg: PeiMain: Updated dispatcher for delayed dispatch
  2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
                   ` (2 preceding siblings ...)
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch Kun Qin
@ 2023-10-10  0:18 ` Kun Qin
  2023-10-11  1:48 ` 回复: [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 gaoliming via groups.io
  4 siblings, 0 replies; 8+ messages in thread
From: Kun Qin @ 2023-10-10  0:18 UTC (permalink / raw)
  To: devel
  Cc: Jian J Wang, Liming Gao, Dandan Bi, Debkumar De, Catharine West,
	John Schock

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496

This change adds a check for PEI dispatcher to continue dispatching when
there are still pending delayed dispatch requests, to be compatible with
newly integrated Delayed Dispatcher PPI interface.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Dandan Bi <dandan.bi@intel.com>
Cc: Debkumar De <debkumar.de@intel.com>
Cc: Catharine West <catharine.west@intel.com>

Co-authored-by: John Schock <joschock@microsoft.com>
Signed-off-by: Kun Qin <kuqin12@gmail.com>
---

Notes:
    v2:
    - Fix up author

 MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
index f7f4cce84174..bec829dc17f3 100644
--- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
+++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
@@ -2013,7 +2013,10 @@ PeiDispatcher (
     //  pass. If we did not dispatch a PEIM/FV there is no point in trying again
     //  as it will fail the next time too (nothing has changed).
     //
-  } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
+    // Also continue dispatch loop if there are outstanding delay-
+    // dispatch registrations still running.
+  } while ((Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass) ||
+           (Private->DelayedDispatchTable->Count > 0));
 }
 
 /**
-- 
2.42.0.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109470): https://edk2.groups.io/g/devel/message/109470
Mute This Topic: https://groups.io/mt/101865811/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface Kun Qin
@ 2023-10-10  8:46   ` Laszlo Ersek
  0 siblings, 0 replies; 8+ messages in thread
From: Laszlo Ersek @ 2023-10-10  8:46 UTC (permalink / raw)
  To: devel, kuqin12; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Mike Turner

On 10/10/23 02:18, Kun Qin wrote:
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496
> 
> This change adds a new interface for the delayed dispatch PPI. This
> new addition allows functional components relying on delayed dispatch
> callbacks to be managed/dispatched with definitive order.
> 
> The full defintion has been added into PI spec.
> 
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> 
> Co-authored-by: Mike Turner <mikeyt@pobox.com>
> Signed-off-by: Kun Qin <kuqin12@gmail.com>
> ---
> 
> Notes:
>     v2:
>     - Fixed PI spec version number to v1.8 [Liming]
> 
>  MdePkg/Include/Ppi/DelayedDispatch.h | 26 ++++++++++++++++++--
>  1 file changed, 24 insertions(+), 2 deletions(-)

I have a question that admittedly targets the spec more than it targets
the implementation.

What is the envisaged programming model / use case for WaitOnEvent? How
are multiple PEIMs to interoperate via the UniqueId GUIDs? Some concrete
use case would be good to know.

Second: the WaitOnEvent function can wait for completion in one of two ways:

(a) by calling back into the PEI dispatcher,

(b) by longjumping to the PEI dispatcher, and then the PEI dispatcher
longjumping back to WaitOnEvent.

Option (b) seems complicated (although not unseen in edk2; we frequently
use StackSwitch for various purposes, and see for example the Exit()
boot service -- that can *only* work with longjump).

Option (a) seems problematic, because if multiple PEIMs use ("nest")
WaitOnEvent, then we get repeated stack frames that all stand for the
PEI dispatcher. Stack space is considered "premium" during PEI; because
-- for example -- otherwise we wouldn't have
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH, opposing
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK.

Thanks,
Laszlo

> 
> diff --git a/MdePkg/Include/Ppi/DelayedDispatch.h b/MdePkg/Include/Ppi/DelayedDispatch.h
> index 098d57758551..0efcfdbfced6 100644
> --- a/MdePkg/Include/Ppi/DelayedDispatch.h
> +++ b/MdePkg/Include/Ppi/DelayedDispatch.h
> @@ -1,5 +1,5 @@
>  /** @file
> -    EFI Delayed Dispatch PPI as defined in the PI 1.7 Specification
> +    EFI Delayed Dispatch PPI as defined in the PI 1.8 Specification
>  
>      Provide timed event service in PEI
>  
> @@ -50,6 +50,7 @@ This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
>    @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
>    @param[in] Function       Function to call back
>    @param[in] Context        Context data
> +  @param[in] UniqueId       GUID for this Delayed Dispatch request.
>    @param[in] Delay          Delay interval
>  
>    @retval EFI_SUCCESS               Function successfully loaded
> @@ -63,9 +64,29 @@ EFI_STATUS
>    IN  EFI_DELAYED_DISPATCH_PPI      *This,
>    IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
>    IN  UINT64                         Context,
> +  IN  EFI_GUID                      *UniqueId   OPTIONAL,
>    IN  UINT32                         Delay
>    );
>  
> +/**
> +  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
> +  to dispatch all registered delayed dispatch entries until *ALL* entries with
> +  UniqueId have completed.
> +
> +  @param[in]     This            The Delayed Dispatch PPI pointer.
> +  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
> +
> +  @retval EFI_SUCCESS            The operation succeeds.
> +  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
> +
> +**/
> +typedef
> +EFI_STATUS
> +(EFIAPI *EFI_DELAYED_DISPATCH_WAIT_ON_EVENT)(
> +  IN  EFI_DELAYED_DISPATCH_PPI      *This,
> +  IN  EFI_GUID                      *UniqueId
> +  );
> +
>  ///
>  /// This PPI is a pointer to the Delayed Dispatch Service.
>  /// This service will be published by the Pei Foundation. The PEI Foundation
> @@ -73,7 +94,8 @@ EFI_STATUS
>  /// execution.
>  ///
>  struct _EFI_DELAYED_DISPATCH_PPI {
> -  EFI_DELAYED_DISPATCH_REGISTER    Register;
> +  EFI_DELAYED_DISPATCH_REGISTER         Register;
> +  EFI_DELAYED_DISPATCH_WAIT_ON_EVENT    WaitOnEvent;
>  };
>  
>  extern EFI_GUID  gEfiPeiDelayedDispatchPpiGuid;



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109481): https://edk2.groups.io/g/devel/message/109481
Mute This Topic: https://groups.io/mt/101865809/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch Kun Qin
@ 2023-10-10 13:14   ` Laszlo Ersek
  0 siblings, 0 replies; 8+ messages in thread
From: Laszlo Ersek @ 2023-10-10 13:14 UTC (permalink / raw)
  To: devel, kuqin12
  Cc: Jian J Wang, Dandan Bi, Liming Gao, Debkumar De, Catharine West,
	Mike Turner

On 10/10/23 02:18, Kun Qin wrote:
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496
>
> This change adds the implementation 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.
>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Dandan Bi <dandan.bi@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> 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@gmail.com>
> ---
>
> Notes:
>     v2:
>     - Fixed function documentation [Liming]
>     - Removed GUID declaration internal to PEI core [Liming]
>     - Removed max entry PCD declaration and use macro instead [Liming]
>     - Added "PRODUCED" in inf [Liming]
>
>  MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 366 ++++++++++++++++++++
>  MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |   3 +
>  MdeModulePkg/Core/Pei/PeiMain.h               |  76 ++++
>  MdeModulePkg/Core/Pei/PeiMain.inf             |   5 +
>  MdeModulePkg/MdeModulePkg.dec                 |   8 +
>  5 files changed, 458 insertions(+)

Please point your "diff.order" git config item to
"BaseTools/Conf/diff.order".

The "BaseTools/Scripts/SetupGit.py" script will do that (and other
things) for you.

Without proper logical ordering of the files in a patch, review is more
difficult. I'm going to quote your hunks out of posting order (i.e.,
I'll quote them in logical order).


> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
> index dd182c02fdf6..cb49ef50b864 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -994,6 +994,14 @@ [PcdsFixedAtBuild]
>    # @ValidList  0x80000006 | 0x03058002
>    gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable|0x03058002|UINT32|0x30001040
>
> +  ## Delayed Dispatch Maximum Delay in us (microseconds)
> +  # Maximum delay for any particular delay request - 5 seconds
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs|5000000|UINT32|0x3000104A
> +
> +  ## Delayed Dispatch timeout in us (microseconds)
> +  # Maximum delay when waiting for completion (ie EndOfPei) - 10 seconds
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeoutUs|10000000|UINT32|0x3000104B
> +
>    ## Mask to control the NULL address detection in code for different phases.
>    #  If enabled, accessing NULL address in UEFI or SMM code can be caught.<BR><BR>
>    #    BIT0    - Enable NULL pointer detection for UEFI.<BR>

Making these fixed-at-build PCDs is not optimal; more on that later.


> diff --git a/MdeModulePkg/Core/Pei/PeiMain.inf b/MdeModulePkg/Core/Pei/PeiMain.inf
> index 0cf357371a16..b2c1e53949de 100644
> --- a/MdeModulePkg/Core/Pei/PeiMain.inf
> +++ b/MdeModulePkg/Core/Pei/PeiMain.inf
> @@ -66,6 +66,7 @@ [LibraryClasses]
>    PeCoffLib
>    PeiServicesTablePointerLib
>    PcdLib
> +  TimerLib
>
>  [Guids]
>    gPeiAprioriFileNameGuid       ## SOMETIMES_CONSUMES   ## File
> @@ -100,6 +101,8 @@ [Ppis]
>    gEfiPeiReset2PpiGuid                          ## SOMETIMES_CONSUMES
>    gEfiSecHobDataPpiGuid                         ## SOMETIMES_CONSUMES
>    gEfiPeiCoreFvLocationPpiGuid                  ## SOMETIMES_CONSUMES
> +  gEfiPeiDelayedDispatchPpiGuid                 ## PRODUCES
> +  gEfiEndOfPeiSignalPpiGuid                     ## CONSUMES
>
>  [Pcd]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxPeiStackSize                  ## CONSUMES
> @@ -112,6 +115,8 @@ [Pcd]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdShadowPeimOnBoot                        ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack                    ## CONSUMES
>    gEfiMdeModulePkgTokenSpaceGuid.PcdMigrateTemporaryRamFirmwareVolumes      ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchMaxDelayUs               ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdDelayedDispatchCompletionTimeoutUs      ## CONSUMES
>
>  # [BootMode]
>  # S3_RESUME             ## SOMETIMES_CONSUMES

OK, end-of-PEI-signal is produced by the DXE IPL PEIM (except on the S3
resume path), and by S3Resume2Pei (on the S3 boot path).


> diff --git a/MdeModulePkg/Core/Pei/PeiMain.h b/MdeModulePkg/Core/Pei/PeiMain.h
> index 556beddad533..542b680c099c 100644
> --- a/MdeModulePkg/Core/Pei/PeiMain.h
> +++ b/MdeModulePkg/Core/Pei/PeiMain.h
> @@ -11,6 +11,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  #include <PiPei.h>
>  #include <Ppi/DxeIpl.h>
> +#include <Ppi/DelayedDispatch.h>
> +#include <Ppi/EndOfPeiPhase.h>
>  #include <Ppi/MemoryDiscovered.h>
>  #include <Ppi/StatusCode.h>
>  #include <Ppi/Reset.h>
> @@ -41,6 +43,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  #include <IndustryStandard/PeImage.h>
>  #include <Library/PeiServicesTablePointerLib.h>
>  #include <Library/MemoryAllocationLib.h>
> +#include <Library/TimerLib.h>
>  #include <Guid/FirmwareFileSystem2.h>
>  #include <Guid/FirmwareFileSystem3.h>
>  #include <Guid/AprioriFileName.h>
> @@ -207,6 +210,29 @@ EFI_STATUS
>
>  #define PEI_CORE_HANDLE_SIGNATURE  SIGNATURE_32('P','e','i','C')
>
> +#define GET_TIME_IN_US()  ((UINT32)DivU64x32(GetTimeInNanoSecond(GetPerformanceCounter ()), 1000))

This is wrong; it violates *both* the GetPerformanceCounter() *and* the
GetTimeInNanoSecond() TimerLib API contracts.

- GetPerformanceCounter() may return tick values in an increasing or
  decreasing order,

- GetPerformanceCounter() may wrap around (in the direction that it is
  counting in),

- the interval from which GetPerformanceCounter() returns tick values
  may not be based on zero.

These characteristics can be retrieved with
GetPerformanceCounterProperties().

Furthermore, GetTimeInNanoSecond() takes a parameter of *elapsed* ticks
(that is, a difference between tick values); it cannot be used on raw
GetPerformanceCounter() output, in the general case.

In August 2017, I wrote a library called TimerTickDiffLib, and proposed
it for MdePkg:

  http://mid.mail-archive.com/8cba2a58-1333-7733-031d-0883dbd844c6@redhat.com

The core of that library is the GetTickDifference() function, which
calculates the elapsed tick count (a difference of tick values)
accounting for both wrap-around and counting direction. The result of
such a circumspect subtraction can be then passed to
GetTimeInNanoSecond().

However... that isn't even the main issue here. The main issue with this
patch is that it attempts to add such scheduling to the PEI core that is
based on an *absolute*, *non-wrapping* time scale. That cannot work,
because in PEI, we have no Real Time (or at least Monotonic Time)
abstraction.

In PI / UEFI, there is EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL.

(Side comment: that protocol is installed on a handle with a NULL
interface pointer -- the driver producing
EFI_REAL_TIME_CLOCK_ARCH_PROTOCOL is supposed to set gRT->GetTime,
gRT->SetTime, gRT->GetWakeupTime and gRT->SetWakeupTime directly.)

However, as far as I know, there is no such abstraction in PEI. One PPI
that comes close is the Required Additional PPI EFI_PEI_STALL_PPI -- but
the Delayed Dispatch PPI is supposed to supersede *exactly that*.

So for implementing the Delayed Dispatch PPI, there are two options:

- either introduce a RealTime PPI, require platforms to provide it, and
  base the Delayed Dispatch PPI on that,

- or build an absolute timescale-based dispatcher in the PEI core (for
  the Delayed Dispatch PPI) *manually*.

The present patch attempts to do the second one, but in a wrong way. The
GET_TIME_IN_US() *usage* (calls) actually seem sensible (from a
superficial skim), but GET_TIME_IN_US() is not implemented correctly at
all.

A correct implementation has to:

- initially call GetPerformanceCounterProperties(),

- periodically (frequently) call GetPerformanceCounter(),

- each time GetPerformanceCounter() is called, calculate the tick
  *difference* (= elapsed tick count) relative to the last call, using
  logic like my function GetTickDifference() -- this relies on the
  performance counter properties fetched earlier,

- translate the tick difference to nanoseconds with
  GetTimeInNanoSecond() --> this gives us a *time* difference,

- *accumulate* the time difference into a monotonically increasing
  "time" global variable that is internal to the PEI Core,

- use this "time" variable as the basis for scheduling delayed events
  (calculating timestamps into the future, and comparing timestamps
  against the current time).

If you want an absolute time-based scheduler, this is the way.

Now, you may want a *remaining time*-based scheduler. In my opinion,
that would be easier. Here's how that might look like:

- Whenever a callback is scheduled, don't try to calculate its absolute
  timestamp after which it should "fire". Instead, only store the
  *remaining* time left, for the callback.

- The way to fetch and calculate small time advances is identical to the
  above (i.e., GetPerformanceCounter(), GetTickDifference(),
  GetTimeInNanoSecond()).

- Rather than accumulating the most recent time difference in each
  iteration, *subtract* the time difference from *every pending* event's
  remaining time. Whichever fall down to, or below, zero, should "fire".

In the absolute approach, you move the global "time" forward, and
compare it against absolute timestamps.

(An extra complication with the absolute time / timestamp approach is
that, as time progresses, your "time" variable may grow (theoretically)
without bounds. However, this complication turns out to be academic. If
your time variable counts in microseconds and is based at zero, then
2^64-1 microseconds amount to approximately 584,942 years by my count;
that's probably enough for any platform's PEI phase to complete. :) )

In the remaining time approach, you shrink all the remaining times
together, and compare them against zero.

With a naive data structure, such as an unordered array or list, a
linear scanning of all pending events is necessary in both approaches.

With a more advanced data structure, such as a priority queue, the
absolute time approach is faster, because once you hit an event at the
front of the queue whose "time has not come yet", you know you can stop
scanning, whereas with the remaining time approach, you still need to
touch all the other events, for subtracting the elapsed number of
nanoseconds.

With only 8 events allowed for pending at any time, a simple array
should be plenty good, even with the remaining times (i.e., subtraction)
approach.

Either way, the current patch is inappropriate. It could lead to lost
notifications or other timing misbehavior, because it violates the
TimerLib API contracts. So, either stick with the absolute idea
(GET_TIME_IN_US), but implement it properly, or else switch to the
"remaining time" (= subtractive) approach.


And then I can get to why the PCDs you propose above are not optimal, in
my opinion. Both time scales above (absolute versus remaining) rest on
time differences, or put more directly, on elapsed tick counts.

Calculating an elapsed tick count is only possible if the performance
counter wraps around *at most once* -- that is, zero times, or one time.
If it wraps around *at least twice*, then a unique elapsed tick count
cannot be calculated.

For example, the performance counter may wrap around three times, but we
may only perceive that the value jumped from near the high-end near the
low-end, and therefore decide that the elapsed tick count is relatively
small. This further leads us to decide that there is more time to wait
before a pending event should be triggered -- meanwhile, that event may
have *seriously* timed out!

So the reason I frown at the PCDs is that, if you put the PEI Core to
*sleep* for such long times (because all events are that far out in the
future, like 4.5 seconds!), then the performance counter may easily wrap
around multiple times while the PEI Core is sleeping.

However... now I realize that the PEI Core actually never sleeps, and
the timeouts are checked in every iteration of the PEI Dispatcher --
it's effectively a busy loop. Knowing that, I agree that the PCDs are
actually safe.

One catch remains though. If a PEIM takes too long before it returns to
the dispatcher -- for example because it interacts with a a slow device,
or manipulates a lot of data in RAM, or because it calls
EFI_PEI_STALL_PPI.Stall() with a very high number of microseconds --,
then the performance counter may wrap around twice or more, again.

Therefore I think the EFI_PEI_STALL_PPI specification should preferably
be extended to warn against long delays. (Similarly to how the UEFI spec
recommends doing any work at the lowest possible TPL for that kind of
work.)

Okay, summary:

- I think the PCDs are viable, after all

- GET_TIME_IN_US() is incorrectly implemented; you certainly need
  something like GetTickDifference from my patch (or just write it from
  scratch), and then either rewrite GET_TIME_IN_US(), accumulating time
  differences, or replace it altogether with a "remaining time"
  approach.

- Represent microsecond counts in UINT64. The outermost UINT32 cast is
  unsettling. 2^32-1 microseconds is approximately 72 minutes. That
  makes me very uncomfortable. Let us not shoot ourselves in the foot
  like that. (I figure a 32-bit microsecond resolution might work if you
  used the "remaining time" approach.)


> +
> +//
> +// Internal structure for delayed dispatch entries.
> +//
> +#pragma pack (push, 1)
> +
> +typedef struct {
> +  EFI_GUID                         UniqueId;
> +  UINT64                           Context;
> +  EFI_DELAYED_DISPATCH_FUNCTION    Function;
> +  UINT32                           DispatchTime;

"DispatchTime" should be UINT64, per above.


> +  UINT32                           MicrosecondDelay;

As far as I can tell, from the rest of the code, storing this field /
value permanantly is superfluous; it is a waste of HOB space.


> +} DELAYED_DISPATCH_ENTRY;
> +
> +typedef struct {
> +  UINT32                    Count;
> +  UINT32                    DispCount;
> +  DELAYED_DISPATCH_ENTRY    Entry[1];     // Actual size based on usage, and cannot exceed DELAYED_DISPATCH_MAX_ENTRIES;
> +} DELAYED_DISPATCH_TABLE;
> +
> +#pragma pack (pop)
> +
>  ///
>  /// Pei Core private data structure instance
>  ///

- I guess these structures are packed because they're going to be stored
  in a HOB, and we're trying to conserve space. OK, but please document
  that reason here.

- Using the "struct hack", that is, declaring the Entry array with 1
  element, is *both* a wart, *and* unnecessary here.

  One, it is a wart because the "struct hack" requires over-indexing the
  array, and that is undefined behavior. (In C99, we have the "flexible
  array member", such as Entry[]; which is well defined.)

  Two, it is unnecessary because you only intend to permit 8 entries in
  the array (see DELAYED_DISPATCH_MAX_ENTRIES below), so all the
  "dynamic" sizing and indexing is just overkill.

  I recommend hoisting the DELAYED_DISPATCH_MAX_ENTRIES macro to the
  header file as well, and declaring this field as
  Entry[DELAYED_DISPATCH_MAX_ENTRIES].


> @@ -307,6 +333,11 @@ struct _PEI_CORE_INSTANCE {
>    // Those Memory Range will be migrated into physical memory.
>    //
>    HOLE_MEMORY_DATA                  HoleData[HOLE_MAX_NUMBER];
> +
> +  //
> +  // Table of delayed dispatch requests
> +  //
> +  DELAYED_DISPATCH_TABLE            *DelayedDispatchTable;
>  };
>
>  ///
> @@ -2038,4 +2069,49 @@ PeiReinitializeFv (
>    IN  PEI_CORE_INSTANCE  *PrivateData
>    );
>
> +/**
> +Register a callback to be called after a minimum delay has occurred.
> +
> +This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
> +

Wrong indentation.


> +  @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
> +  @param[in] Function       Function to call back
> +  @param[in] Context        Context data
> +  @param[in] UniqueId       GUID for this Delayed Dispatch request.
> +  @param[in] Delay          Delay interval
> +
> +  @retval EFI_SUCCESS               Function successfully loaded
> +  @retval EFI_INVALID_PARAMETER     One of the Arguments is not supported
> +  @retval EFI_OUT_OF_RESOURCES      No more entries
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchRegister (
> +  IN  EFI_DELAYED_DISPATCH_PPI       *This,
> +  IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
> +  IN  UINT64                         Context,
> +  IN  EFI_GUID                       *UniqueId   OPTIONAL,
> +  IN  UINT32                         Delay
> +  );
> +
> +/**
> +  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
> +  to dispatch all registered delayed dispatch entries until *ALL* entries with
> +  UniqueId have completed.
> +
> +  @param[in]     This            The Delayed Dispatch PPI pointer.
> +  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
> +
> +  @retval EFI_SUCCESS            The operation succeeds.
> +  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchWaitOnUniqueId (
> +  IN EFI_DELAYED_DISPATCH_PPI  *This,
> +  IN EFI_GUID                  *UniqueId
> +  );
> +
>  #endif

Well, calling the GUID "UniqueId" is a bug in the PI spec then -- it is
not supposed to be unique at all! It's similar to a UEFI event *group*
ID. Anyway.


>
> diff --git a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
> index 5f32ebb560ae..f7f4cce84174 100644
> --- a/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
> +++ b/MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
> @@ -3,14 +3,354 @@
>
>  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
>  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
> +Copyright (c) Microsoft Corporation.
>  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  **/
>
>  #include "PeiMain.h"
>
> +//
> +// Maximal number of Delayed Dispatch entries supported
> +//
> +#define DELAYED_DISPATCH_MAX_ENTRIES  8
> +
> +//
> +// Utility global variables
> +//
> +
> +// Delayed Dispatch table GUID
> +EFI_GUID  gEfiDelayedDispatchTableGuid = {
> +  0x4b733449, 0x8eff, 0x488c, { 0x92, 0x1a, 0x15, 0x4a, 0xda, 0x25, 0x18, 0x07 }
> +};
> +

This is non-idiomatic. Even if we don't mean this HOB GUID for public
consumption, GUID definitions like this belong in the package DEC file.


> +/**
> +  DelayedDispatchDispatcher
> +
> +  ayed Dispach cycle (ie one pass) through each entry, calling functions when their
> +  e has expired.  When UniqueId is specified, if there are any of the specified entries
> +  the dispatch queue during dispatch, repeat the DelayedDispatch cycle.

Three vertical columns, on the left hand side of this comment block, are
missing.


> +
> +  @param DelayedDispatchTable  Pointer to dispatch table
> +  @param OPTIONAL              UniqueId used to insure particular time is met.
> +
> +  @return BOOLEAN
> +**/
> +BOOLEAN
> +DelayedDispatchDispatcher (
> +  IN DELAYED_DISPATCH_TABLE  *DelayedDispatchTable,
> +  IN EFI_GUID                *UniqueId           OPTIONAL
> +  );
> +
> +/**
> +  DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch
> +  entries are complete before exiting PEI.
> +
> +  @param[in] PeiServices   - Pointer to PEI Services Table.
> +  @param[in] NotifyDesc    - Pointer to the descriptor for the Notification event that
> +                             caused this function to execute.
> +  @param[in] Ppi           - Pointer to the PPI data associated with this function.
> +
> +  @retval EFI_STATUS       - Always return EFI_SUCCESS
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchOnEndOfPei (
> +  IN EFI_PEI_SERVICES           **PeiServices,
> +  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,
> +  IN VOID                       *Ppi
> +  );
> +
> +EFI_DELAYED_DISPATCH_PPI  mDelayedDispatchPpi  = { PeiDelayedDispatchRegister, PeiDelayedDispatchWaitOnUniqueId };
> +EFI_PEI_PPI_DESCRIPTOR    mDelayedDispatchDesc = {
> +  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
> +  &gEfiPeiDelayedDispatchPpiGuid,
> +  &mDelayedDispatchPpi
> +};
> +
> +EFI_PEI_NOTIFY_DESCRIPTOR  mDelayedDispatchNotifyDesc = {
> +  EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
> +  &gEfiEndOfPeiSignalPpiGuid,
> +  PeiDelayedDispatchOnEndOfPei
> +};
> +
> +/**
> +  Helper function to look up DELAYED_DISPATCH_TABLE published in HOB.
> +
> +  @return Pointer to DELAYED_DISPATCH_TABLE from HOB
> +**/
> +DELAYED_DISPATCH_TABLE *
> +GetDelayedDispatchTable (
> +  VOID
> +  )
> +{
> +  EFI_HOB_GUID_TYPE  *GuidHob;
> +
> +  GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
> +  if (NULL == GuidHob) {
> +    DEBUG ((DEBUG_ERROR, "Delayed Dispatch PPI ERROR - Delayed Dispatch Hob not available.\n"));
> +    ASSERT (FALSE);
> +    return NULL;
> +  }

I don't understand either the DEBUG_ERROR here, *or* the ASSERT().

All call sites of GetDelayedDispatchTable() check the return value
against NULL, and return EFI_UNSUPPORTED outwards, if the retval is
NULL. I.e., those call sites seem careful enough, so the ASSERT() here
is uncalled for.


> +
> +  return (DELAYED_DISPATCH_TABLE *)GET_GUID_HOB_DATA (GuidHob);
> +}
> +
> +/**
> +  Register a callback to be called after a minimum delay has occurred.
> +
> +  This service is the single member function of the EFI_DELAYED_DISPATCH_PPI
> +
> +  @param[in] This           Pointer to the EFI_DELAYED_DISPATCH_PPI instance
> +  @param[in] Function       Function to call back
> +  @param[in] Context        Context data
> +  @param[in] UniqueId       GUID for this Delayed Dispatch request.
> +  @param[in] Delay          Delay interval
> +
> +  @retval EFI_SUCCESS               Function successfully loaded
> +  @retval EFI_INVALID_PARAMETER     One of the Arguments is not supported
> +  @retval EFI_OUT_OF_RESOURCES      No more entries
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchRegister (
> +  IN  EFI_DELAYED_DISPATCH_PPI       *This,
> +  IN  EFI_DELAYED_DISPATCH_FUNCTION  Function,
> +  IN  UINT64                         Context,
> +  IN  EFI_GUID                       *UniqueId   OPTIONAL,
> +  IN  UINT32                         Delay
> +  )
> +{
> +  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
> +  DELAYED_DISPATCH_ENTRY  *Entry;
> +
> +  // Check input parameters
> +  if ((NULL == Function) || (Delay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) || (NULL == This)) {
> +    DEBUG ((DEBUG_ERROR, "%a Invalid parameter\n", __func__));

Not sure if you really need this DEBUG, but if you keep it, make it more
informative, I'd suggest. Log the function name, UniqueId if any, and
Delay.


> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  // Get delayed dispatch table
> +  DelayedDispatchTable = GetDelayedDispatchTable ();
> +  if (NULL == DelayedDispatchTable) {
> +    DEBUG ((DEBUG_ERROR, "%a Unable to locate dispatch table\n", __func__));
> +    return EFI_UNSUPPORTED;
> +  }

DEBUG_ERROR superfluous, GetDelayedDispatchTable() already logs an
error; *plus* a DEBUG_ERROR here is inconsistent with *other* call sites
of GetDelayedDispatchTable(), which does not log an error.


> +
> +  // Check for available entry slots
> +  if (DelayedDispatchTable->Count >= DELAYED_DISPATCH_MAX_ENTRIES) {
> +    ASSERT (DelayedDispatchTable->Count < DELAYED_DISPATCH_MAX_ENTRIES);
> +    DEBUG ((DEBUG_ERROR, "%a Too many entries requested\n", __func__));
> +    return EFI_OUT_OF_RESOURCES;
> +  }

Wrong for multiple reasons.

- Count > MAX is impossible, so if you want to assert something, assert
  Count <= MAX, *before* the "if".

- Accordingly, the condition of the "if" should only check for equality
  (==), "table full".

- the ASSERT() *inside* the "if" is totally bogus; please remove it.
  Note that, as proposed, the ASSERT()'s condition is the exact opposite
  of the "if"'s condition, so once you enter the "if" body, the ASSERT
  is sure to fire!

- Asserting that Count be *strictly smaller* than MAX is wrong in
  itself. The caller may well call this function with the table full (8
  entries), which will trigger the ASSERT(). But such a call is not an
  invariant violation! Simply return EFI_OUT_OF_RESOURCES.

In short:

  ASSERT (DelayedDispatchTable->Count <= DELAYED_DISPATCH_MAX_ENTRIES);
  if (DelayedDispatchTable->Count == DELAYED_DISPATCH_MAX_ENTRIES) {
    DEBUG ((DEBUG_ERROR, "%a Too many entries requested\n", __func__));
    return EFI_OUT_OF_RESOURCES;
  }


> +
> +  Entry               = &(DelayedDispatchTable->Entry[DelayedDispatchTable->Count]);

The parens are weird.


> +  Entry->Function     = Function;
> +  Entry->Context      = Context;
> +  Entry->DispatchTime = GET_TIME_IN_US () + Delay;

Independently of everything else said thus far, you should please use
SafeIntLib for all timestamp calculations in this patch. That's why
SafeIntLib exists.


> +  if (NULL != UniqueId) {

Personally I love Yoda conditionals, but in edk2, they are not
idiomatic.

Also, a *negative* comparison in such an "if" that has an "else" branch
is questionable style. Rather use the positive comparison, and swap the
branches around.


> +    CopyGuid (&Entry->UniqueId, UniqueId);
> +  } else {
> +    ZeroMem (&Entry->UniqueId, sizeof (EFI_GUID));
> +  }
> +
> +  Entry->MicrosecondDelay = Delay;
> +  DelayedDispatchTable->Count++;
> +
> +  DEBUG ((DEBUG_INFO, "%a  Adding dispatch Entry\n", __func__));
> +  DEBUG ((DEBUG_INFO, "    Requested Delay = %d\n", Delay));

"Delay" is UINT32, please log it with %u.


> +  DEBUG ((DEBUG_INFO, "    Trigger Time = %d\n", Entry->DispatchTime));

"DispatchTime" should be UINT64 (per above), so the right way to log it
is %Lu.


> +  DEBUG ((DEBUG_INFO, "    Context = 0x%08lx\n", Entry->Context));

"Context" is UINT64, so %lx is fine, but why 8 for the minimum width
rather than 16?


> +  DEBUG ((DEBUG_INFO, "    Function = %p\n", Entry->Function));

%p is for logging a pointer-to-void, not a pointer-to-function. The
pristine way is this:

  DEBUG ((DEBUG_INFO, "    Function = %Lx\n", (UINT64)(UINTN)Entry->Function));

because:

- the funcptr can be converted to an integer, per ISO C,

- UINTN has the same width as our function pointers, so no complaints
  from compilers, and all function addresses can be represented in UINTN

- printing a UINTN portably requires us to cast it to UINT64 (a no-op on
  64-bit platforms and an actual widening on 32-bit platforms), because
  that way we can print the value with the *common* format specifier
  %Lx.


> +  DEBUG ((DEBUG_INFO, "    GuidHandle = %g\n", &(Entry->UniqueId)));

- The parens are weird.

- The parameter is called "UniqueI", why log it as "GuidHandle"?


> +
> +  if (0 == Delay) {

More Yoda.


> +    // Force early dispatch point
> +    DelayedDispatchDispatcher (DelayedDispatchTable, NULL);
> +  }
> +
> +  return EFI_SUCCESS;
> +}

(I can't even look at the higher logic at this point.)


> +
> +/**
> +  DelayedDispatchDispatcher
> +
> +  Delayed Dispach cycle (ie one pass) through each entry, calling functions when their
> +  time has expired.  When UniqueId is specified, if there are any of the specified entries
> +  in the dispatch queue during dispatch, repeat the DelayedDispatch cycle.
> +
> +  @param DelayedDispatchTable  Pointer to dispatch table
> +  @param OPTIONAL              UniqueId used to insure particular time is met.
> +
> +  @return BOOLEAN
> +**/
> +BOOLEAN
> +DelayedDispatchDispatcher (
> +  IN DELAYED_DISPATCH_TABLE  *DelayedDispatchTable,
> +  IN EFI_GUID                *UniqueId           OPTIONAL
> +  )
> +{
> +  BOOLEAN                 Dispatched;
> +  UINT32                  TimeCurrent;
> +  UINT32                  MaxDispatchTime;
> +  UINTN                   Index1;
> +  BOOLEAN                 UniqueIdPresent;
> +  DELAYED_DISPATCH_ENTRY  *Entry;
> +
> +  Dispatched      = FALSE;
> +  UniqueIdPresent = TRUE;
> +  MaxDispatchTime = GET_TIME_IN_US () + FixedPcdGet32 (PcdDelayedDispatchCompletionTimeoutUs);
> +  while ((DelayedDispatchTable->Count > 0) && (UniqueIdPresent)) {
> +    UniqueIdPresent = FALSE;
> +    DelayedDispatchTable->DispCount++;
> +
> +    // If dispatching is messed up, clear DelayedDispatchTable and exit.
> +    TimeCurrent =  GET_TIME_IN_US ();
> +    if (TimeCurrent > MaxDispatchTime) {
> +      DEBUG ((DEBUG_ERROR, "%a - DelayedDispatch Completion timeout!\n", __func__));
> +      ReportStatusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE), (EFI_SOFTWARE_PEI_CORE | EFI_SW_EC_ABORTED));
> +      ASSERT (FALSE);
> +      DelayedDispatchTable->Count = 0;
> +      break;
> +    }
> +
> +    // Check each entry in the table for possible dispatch
> +    for (Index1 = 0; Index1 < DelayedDispatchTable->Count;) {
> +      Entry = &(DelayedDispatchTable->Entry[Index1]);
> +      // If UniqueId is present, insure there is an additional check of the table.
> +      if (NULL != UniqueId) {
> +        if (CompareGuid (UniqueId, &Entry->UniqueId)) {
> +          UniqueIdPresent = TRUE;
> +        }
> +      }
> +
> +      TimeCurrent =  GET_TIME_IN_US ();
> +      if (TimeCurrent >= Entry->DispatchTime) {
> +        // Time expired, invoked the function
> +        DEBUG ((
> +          DEBUG_ERROR,
> +          "Delayed dispatch entry %d @ %p, Target=%d, Act=%d Disp=%d\n",
> +          Index1,
> +          Entry->Function,
> +          Entry->DispatchTime,
> +          TimeCurrent,
> +          DelayedDispatchTable->DispCount
> +          ));
> +        Dispatched              = TRUE;
> +        Entry->MicrosecondDelay = 0;
> +        Entry->Function (
> +                 &Entry->Context,
> +                 &Entry->MicrosecondDelay
> +                 );
> +        DEBUG ((DEBUG_ERROR, "Delayed dispatch Function returned delay=%d\n", Entry->MicrosecondDelay));
> +        if (0 == Entry->MicrosecondDelay) {
> +          // NewTime = 0 = delete this entry from the table
> +          DelayedDispatchTable->Count--;
> +          CopyMem (Entry, Entry+1, sizeof (DELAYED_DISPATCH_ENTRY) * (DelayedDispatchTable->Count - Index1));
> +        } else {
> +          if (Entry->MicrosecondDelay > FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs)) {
> +            DEBUG ((DEBUG_ERROR, "%a Illegal new delay %d requested\n", __func__, Entry->MicrosecondDelay));
> +            ASSERT (FALSE);
> +            Entry->MicrosecondDelay = FixedPcdGet32 (PcdDelayedDispatchMaxDelayUs);
> +          }
> +
> +          // NewTime != 0 - update the time from us to Dispatch time
> +          Entry->DispatchTime =  GET_TIME_IN_US () + Entry->MicrosecondDelay;
> +          Index1++;
> +        }
> +      } else {
> +        Index1++;
> +      }
> +    }
> +  }
> +
> +  return Dispatched;
> +}

Side comment: I have now filed
<https://mantis.uefi.org/mantis/view.php?id=2424>, because the PI v1.8
specification includes EFI_DELAYED_DISPATCH_PPI in the wrong volume (and
there are some other issues with it, too).

My main point: this function, DelayedDispatchDispatcher() does not do
*at all* what it is supposed to do, per spec.

Note that PeiDelayedDispatchWaitOnUniqueId() -- below -- is the function
that we expose as "EFI_DELAYED_DISPATCH_PPI.WaitOnEvent" (the
WaitOnEvent member function is introduced in patch#2 of this series). In
turn, PeiDelayedDispatchWaitOnUniqueId() delegates the bulk of the work
to this function, DelayedDispatchDispatcher().

Therefore, the PI spec's language *applies* to this function. Let me
quote the spec:


| WaitOnEvent
|
|   Pause current process and allow other components to continue to
|   dispatch until all entries with specified “Unique ID” have
|   completed.
|
| [...]
|
| Summary
|
|   Pause current process and allow other components to continue to
|   dispatch until all entries with specified “Unique ID” have
|   completed.
|
| [...]
|
| Description
|
|   This function is invoked by a PEIM to wait until all specified
|   UniqueId events have been dispatched. The other events will continue
|   to dispatch while this process is being paused.

But that's not what DelayedDispatchDispatcher() implements at all.

DelayedDispatchDispatcher() implements a busy loop, one that spins until
all entries marked with the GUID "time out" (i.e., can be invoked and
dequeued).

There is a safety time limit on this busy loop
(PcdDelayedDispatchCompletionTimeoutUs), but that's irrelevant now.

The problem is that this busy loop does not transfer control to "other
events" or "other components" *at all*. The PEI Dispatcher has no chance
to load further PEIMs, and to notify waiters if new PPIs are installed.

So I don't understand what this function tries to do. It does not do
what the spec says it should do. Per spec, this function should
reactivate the PEI Core Dispatcher loop, via direct call or longjump
(see my earlier questions under this patch series), and allow the PEI
Core Dispatcher loop to proceed with *both* the loading of independent
PEIMs *and* the delayed dispatch functions.

... Even if we assume this function does the right thing (which I don't
believe it does), there are a number of warts in it:

- The DispCount field seems to count the number of iterations around the
  *outermost* loops. What is that good for? This field is only consumed
  in some DEBUG messages. The field certainly doesn't count the number
  of *actually dispatching* a queued function.

- Incorrect format specifiers in DEBUG messages.

- The whole "dispatching is messed up" branch, with an ASSERT(FALSE) in
  it. I figure that is meant to defend against a situation when some
  delayed function keeps re-queueing itself, and so the outer loop just
  never ends.

  But this circumstance is not described in the PI spec at all, and
  handling it with an ASSERT(FALSE) is certainly a recipe for disaster.
  More precisely, handling it differently between DEBUG and RELEASE
  builds is a disaster. In DEBUG builds, execution will stop, and you'll
  know something is wrong with your PEI phase. In RELEASE builds
  however, the caller will see EFI_DELAYED_DISPATCH_PPI.WaitOnEvent()
  return as if everything were fine (i.e., as if all delayed functions
  had completed), and happily proceed to consume potentially
  uninitialized memory, used potentially uninitialized devices, and...
  hope for the best? Bad.

- Issues I pointed out earlier: broken implementation of GET_TIME_IN_US,
  "MicrosecondDelay" being a superfluous field (wasting HOB space), etc.

- More weird and unneeded parens after the address-of operator &.

- I may have missed several, because I'm too tired now.


> +
> +/**
> +  Wait on a registered Delayed Dispatch unit that has a UniqueId.  Continue
> +  to dispatch all registered delayed dispatch entries until *ALL* entries with
> +  UniqueId have completed.
> +
> +  @param[in]     This            The Delayed Dispatch PPI pointer.
> +  @param[in]     UniqueId        UniqueId of delayed dispatch entry.
> +
> +  @retval EFI_SUCCESS            The operation succeeds.
> +  @retval EFI_INVALID_PARAMETER  The parameters are invalid.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchWaitOnUniqueId (
> +  IN EFI_DELAYED_DISPATCH_PPI  *This,
> +  IN EFI_GUID                  *UniqueId
> +  )
> +{
> +  PERF_FUNCTION_BEGIN ();
> +  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
> +
> +  // Get delayed dispatch table
> +  DelayedDispatchTable = GetDelayedDispatchTable ();
> +  if (NULL == DelayedDispatchTable) {
> +    PERF_FUNCTION_END ();
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if ((NULL == UniqueId) || (IsZeroGuid (UniqueId))) {
> +    ASSERT (FALSE);
> +    PERF_FUNCTION_END ();
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Delayed dispatch on %g. Count=%d, DispatchCount=%d\n", UniqueId, DelayedDispatchTable->Count, DelayedDispatchTable->DispCount));
> +  PERF_EVENT_SIGNAL_BEGIN (UniqueId);
> +  DelayedDispatchDispatcher (DelayedDispatchTable, UniqueId);
> +  PERF_EVENT_SIGNAL_END (UniqueId);
> +
> +  PERF_FUNCTION_END ();
> +  return EFI_SUCCESS;
> +}
> +

Rather than multiplicating PERF_FUNCTION_END(), this function should
have an "Exit:" label, and use gotos, a Status variable, and move
PERF_FUNCTION_END after "Exit:".

Also, what good is the ASSERT(FALSE) when the PI spec explicitly
documents EFI_INVALID_PARAMETER? Even the function leading comment
specifies EFI_INVALID_PARAMETER -- but the code returns -- after
ASSERT(FALSE)... -- EFI_UNSUPPORTED.

>  /**
> +  DelayedDispatch End of PEI callback function. Insure that all of the delayed dispatch
> +  entries are complete before exiting PEI.
>
> +  @param[in] PeiServices   - Pointer to PEI Services Table.
> +  @param[in] NotifyDesc    - Pointer to the descriptor for the Notification event that
> +                             caused this function to execute.
> +  @param[in] Ppi           - Pointer to the PPI data associated with this function.
> +
> +  @retval EFI_STATUS       - Always return EFI_SUCCESS
> +**/
> +EFI_STATUS
> +EFIAPI
> +PeiDelayedDispatchOnEndOfPei (
> +  IN EFI_PEI_SERVICES           **PeiServices,
> +  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDesc,
> +  IN VOID                       *Ppi
> +  )
> +{
> +  DELAYED_DISPATCH_TABLE  *DelayedDispatchTable;
> +
> +  // Get delayed dispatch table
> +  DelayedDispatchTable = GetDelayedDispatchTable ();
> +  if (NULL == DelayedDispatchTable) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  PERF_INMODULE_BEGIN ("PerfDelayedDispatchEndOfPei");
> +  while (DelayedDispatchTable->Count > 0) {
> +    DelayedDispatchDispatcher (DelayedDispatchTable, NULL);
> +  }
> +
> +  DEBUG ((DEBUG_ERROR, "%a Count of dispatch cycles is %d\n", __func__, DelayedDispatchTable->DispCount));
> +  PERF_INMODULE_END ("PerfDelayedDispatchEndOfPei");
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
>    Discover all PEIMs and optional Apriori file in one FV. There is at most one
>    Apriori file in one FV.
>
> @@ -1365,12 +1705,31 @@ PeiDispatcher (
>    EFI_PEI_FILE_HANDLE     SaveCurrentFileHandle;
>    EFI_FV_FILE_INFO        FvFileInfo;
>    PEI_CORE_FV_HANDLE      *CoreFvHandle;
> +  EFI_HOB_GUID_TYPE       *GuidHob;
> +  UINT32                  TableSize;
>
>    PeiServices    = (CONST EFI_PEI_SERVICES **)&Private->Ps;
>    PeimEntryPoint = NULL;
>    PeimFileHandle = NULL;
>    EntryPoint     = 0;
>
> +  if (NULL == Private->DelayedDispatchTable) {
> +    GuidHob = GetFirstGuidHob (&gEfiDelayedDispatchTableGuid);
> +    if (NULL != GuidHob) {
> +      Private->DelayedDispatchTable = (DELAYED_DISPATCH_TABLE *)(GET_GUID_HOB_DATA (GuidHob));
> +    } else {
> +      TableSize                     = sizeof (DELAYED_DISPATCH_TABLE) + ((DELAYED_DISPATCH_MAX_ENTRIES - 1) * sizeof (DELAYED_DISPATCH_ENTRY));
> +      Private->DelayedDispatchTable = BuildGuidHob (&gEfiDelayedDispatchTableGuid, TableSize);
> +      if (NULL != Private->DelayedDispatchTable) {
> +        ZeroMem (Private->DelayedDispatchTable, TableSize);
> +        Status = PeiServicesInstallPpi (&mDelayedDispatchDesc);
> +        ASSERT_EFI_ERROR (Status);
> +        Status = PeiServicesNotifyPpi (&mDelayedDispatchNotifyDesc);
> +        ASSERT_EFI_ERROR (Status);
> +      }
> +    }
> +  }
> +
>    if ((Private->PeiMemoryInstalled) &&
>        (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
>         (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) ||

Terrible ereror handling with ASSERT_EFI_ERROR().

Sorry, this review tired me out; I've been at it for like half a day
now, and this patch is extremely immature. I don't think I'd like to
review the next version.

Laszlo

> @@ -1621,6 +1980,13 @@ PeiDispatcher (
>              }
>            }
>          }
> +
> +        // Dispatch pending delalyed dispatch requests
> +        if (NULL != Private->DelayedDispatchTable) {
> +          if (DelayedDispatchDispatcher (Private->DelayedDispatchTable, NULL)) {
> +            ProcessDispatchNotifyList (Private);
> +          }
> +        }
>        }
>
>        //
> 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 = (EFI_PEI_FILE_HANDLE *)((UINT8 *)OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
>        }
>
> +      // Force relocating the dispatch table
> +      OldCoreData->DelayedDispatchTable = NULL;
> +
>        //
>        // Fixup for PeiService's address
>        //



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109494): https://edk2.groups.io/g/devel/message/109494
Mute This Topic: https://groups.io/mt/101865810/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/leave/12367111/7686176/1913456212/xyzzy [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 8+ messages in thread

* 回复: [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8
  2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
                   ` (3 preceding siblings ...)
  2023-10-10  0:18 ` [edk2-devel] [PATCH v2 4/4] MdeModulePkg: PeiMain: Updated dispatcher for " Kun Qin
@ 2023-10-11  1:48 ` gaoliming via groups.io
  4 siblings, 0 replies; 8+ messages in thread
From: gaoliming via groups.io @ 2023-10-11  1:48 UTC (permalink / raw)
  To: devel, kuqin12
  Cc: 'Michael D Kinney', 'Zhiguang Liu',
	'Jian J Wang', 'Dandan Bi', 'Debkumar De',
	'Catharine West'

Kun:
  Thanks for your update. I have no other comments.  Reviewed-by: Liming Gao
<gaoliming@byosoft.com.cn>

Thanks
Liming
> -----邮件原件-----
> 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Kun Qin
> 发送时间: 2023年10月10日 8:19
> 收件人: devel@edk2.groups.io
> 抄送: Michael D Kinney <michael.d.kinney@intel.com>; Liming Gao
> <gaoliming@byosoft.com.cn>; Zhiguang Liu <zhiguang.liu@intel.com>; Jian J
> Wang <jian.j.wang@intel.com>; Dandan Bi <dandan.bi@intel.com>;
> Debkumar De <debkumar.de@intel.com>; Catharine West
> <catharine.west@intel.com>
> 主题: [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4496
> 
> This patch series is a follow-up of previous submission:
> https://edk2.groups.io/g/devel/message/107111
> 
> The main changes between v1 and v2 patches are:
>   - Fixed function documentation
>   - Removed GUID declaration internal to PEI core
>   - Removed max entry PCD declaration and use macro instead
> 
> Patch branch: https://github.com/kuqin12/edk2/tree/Delayed_Dispatch_v3
> 
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Dandan Bi <dandan.bi@intel.com>
> Cc: Debkumar De <debkumar.de@intel.com>
> Cc: Catharine West <catharine.west@intel.com>
> 
> Kun Qin (4):
>   MdePkg: DelayedDispatch: Correct PPI descriptions
>   MdePkg: DelayedDispatch: Added WaitOnEvent interface
>   MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch
>   MdeModulePkg: PeiMain: Updated dispatcher for delayed dispatch
> 
>  MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c | 371
> +++++++++++++++++++-
>  MdeModulePkg/Core/Pei/PeiMain/PeiMain.c       |   3 +
>  MdeModulePkg/Core/Pei/PeiMain.h               |  76 ++++
>  MdeModulePkg/Core/Pei/PeiMain.inf             |   5 +
>  MdeModulePkg/MdeModulePkg.dec                 |   8 +
>  MdePkg/Include/Ppi/DelayedDispatch.h          |  41 ++-
>  6 files changed, 494 insertions(+), 10 deletions(-)
> 
> --
> 2.42.0.windows.2
> 
> 
> 
> 
> 





-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109504): https://edk2.groups.io/g/devel/message/109504
Mute This Topic: https://groups.io/mt/101889001/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-10-11  1:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-10  0:18 [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 Kun Qin
2023-10-10  0:18 ` [edk2-devel] [PATCH v2 1/4] MdePkg: DelayedDispatch: Correct PPI descriptions Kun Qin
2023-10-10  0:18 ` [edk2-devel] [PATCH v2 2/4] MdePkg: DelayedDispatch: Added WaitOnEvent interface Kun Qin
2023-10-10  8:46   ` Laszlo Ersek
2023-10-10  0:18 ` [edk2-devel] [PATCH v2 3/4] MdeModulePkg: PeiMain: Introduce implementation of delayed dispatch Kun Qin
2023-10-10 13:14   ` Laszlo Ersek
2023-10-10  0:18 ` [edk2-devel] [PATCH v2 4/4] MdeModulePkg: PeiMain: Updated dispatcher for " Kun Qin
2023-10-11  1:48 ` 回复: [edk2-devel] [PATCH v2 0/4] Implement Delayed Dispatch per PI v1.8 gaoliming via groups.io

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox