]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/Include/Library/NestedInterruptTplLib.h
OvmfPkg: Add library to handle TPL from within nested interrupt handlers
[mirror_edk2.git] / OvmfPkg / Include / Library / NestedInterruptTplLib.h
diff --git a/OvmfPkg/Include/Library/NestedInterruptTplLib.h b/OvmfPkg/Include/Library/NestedInterruptTplLib.h
new file mode 100644 (file)
index 0000000..0ead6e4
--- /dev/null
@@ -0,0 +1,87 @@
+/** @file\r
+  Handle raising and lowering TPL from within nested interrupt handlers.\r
+\r
+  Allows interrupt handlers to safely raise and lower the TPL to\r
+  dispatch event notifications, correctly allowing for nested\r
+  interrupts to occur without risking stack exhaustion.\r
+\r
+  Copyright (C) 2022, Fen Systems Ltd.\r
+\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+**/\r
+\r
+#ifndef __NESTED_INTERRUPT_TPL_LIB__\r
+#define __NESTED_INTERRUPT_TPL_LIB__\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Uefi/UefiSpec.h>\r
+#include <Protocol/DebugSupport.h>\r
+\r
+///\r
+/// State shared between all invocations of a nested interrupt handler.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Highest TPL that is currently the target of a call to\r
+  /// RestoreTPL() by an instance of this interrupt handler.\r
+  ///\r
+  EFI_TPL    InProgressRestoreTPL;\r
+  ///\r
+  /// Flag used to defer a call to RestoreTPL() from an inner instance\r
+  /// of the interrupt handler to an outer instance of the same\r
+  /// interrupt handler.\r
+  ///\r
+  BOOLEAN    DeferredRestoreTPL;\r
+} NESTED_INTERRUPT_STATE;\r
+\r
+/**\r
+  Raise the task priority level to TPL_HIGH_LEVEL.\r
+\r
+  @param  None.\r
+\r
+  @return The task priority level at which the interrupt occurred.\r
+**/\r
+EFI_TPL\r
+EFIAPI\r
+NestedInterruptRaiseTPL (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Lower the task priority back to the value at which the interrupt\r
+  occurred.\r
+\r
+  This is unfortunately messy.  UEFI requires us to support nested\r
+  interrupts, but provides no way for an interrupt handler to call\r
+  RestoreTPL() without implicitly re-enabling interrupts.  In a\r
+  virtual machine, it is possible for a large burst of interrupts to\r
+  arrive.  We must prevent such a burst from leading to stack\r
+  exhaustion, while continuing to allow nested interrupts to occur.\r
+\r
+  Since nested interrupts are permitted, an interrupt handler may be\r
+  invoked as an inner interrupt handler while an outer instance of the\r
+  same interrupt handler is still inside its call to RestoreTPL().\r
+\r
+  To avoid stack exhaustion, this call may therefore (when provably\r
+  safe to do so) defer the actual TPL lowering to be performed by an\r
+  outer instance of the same interrupt handler.\r
+\r
+  @param InterruptedTPL        The task priority level at which the interrupt\r
+                               occurred, as previously returned from\r
+                               NestedInterruptRaiseTPL().\r
+\r
+  @param SystemContext         A pointer to the system context when the\r
+                               interrupt occurred.\r
+\r
+  @param IsrState              A pointer to the state shared between all\r
+                               invocations of the nested interrupt handler.\r
+**/\r
+VOID\r
+EFIAPI\r
+NestedInterruptRestoreTPL (\r
+  IN EFI_TPL                     InterruptedTPL,\r
+  IN OUT EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN OUT NESTED_INTERRUPT_STATE  *IsrState\r
+  );\r
+\r
+#endif // __NESTED_INTERRUPT_TPL_LIB__\r