The Realm Aperture Management Protocol (RAMP) is used to manage
the sharing of buffers between the Guest and Host. It configures
the memory regions as Protected EMPTY or Protected RAM by calling
RSI_IPA_STATE_SET command. The RAMP provides interfaces that device
drivers can use to open/close apertures for sharing buffers.

The RAMP also keeps track of the apertures that have been opened
and closes them on ExitBootServices. It also registers for reset
notification and closes all open apertures before the platform
resets the system.

Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
Cc: Leif Lindholm <quic_llind...@quicinc.com>
Cc: Gerd Hoffmann <kra...@redhat.com>
Signed-off-by: Sami Mujawar <sami.muja...@arm.com>
---
 ArmVirtPkg/ArmVirtPkg.dec                                                      
      |   3 +
 ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h                  
      | 103 +++
 
ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c
   | 658 ++++++++++++++++++++
 
ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf
 |  48 ++
 4 files changed, 812 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec
index 
d521e107ddff15e6dc585e3a63567e3ad817189f..a6701ed3f88b9976110992dda22c11eea735cc4c
 100644
--- a/ArmVirtPkg/ArmVirtPkg.dec
+++ b/ArmVirtPkg/ArmVirtPkg.dec
@@ -44,6 +44,9 @@ [PcdsFeatureFlag]
   #
   gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|FALSE|BOOLEAN|0x00000004
 
+[Protocols]
+  gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 
0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } }
+
 [PcdsFixedAtBuild, PcdsPatchableInModule]
   ##
   # This is the physical address of Rsdp which is the core struct of Acpi.
diff --git a/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h 
b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h
new file mode 100644
index 
0000000000000000000000000000000000000000..0f45fd296fd54ec536ed3d4bd7725350ab487295
--- /dev/null
+++ b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h
@@ -0,0 +1,103 @@
+/** @file
+  Realm Aperture Management Protocol (RAMP)
+  On Arm CCA Systems the Realm protects access and visibility of Guest memory
+  and code execution from software outside the realm.
+
+  However, software executing in a Realm needs to interact with the external
+  world. This may be done using virtualised disk, network interfaces, etc.
+  The drivers for these virtualised devices need to share buffers with the host
+  OS to exchange information/data.
+
+  Since the Guest memory is protected by the Realm, the host cannot access 
these
+  buffers unless the IPA state of the buffers is changed to Protected EMPTY by
+  the software executing in the Realm.
+
+  By enabling the sharing of the buffers, we are essentially opening an
+  aperture so that the host OS can access the range of pages that are shared.
+
+  The virtual firmware (Guest firmware) needs a mechanism to manage the sharing
+  of buffers. The Realm Aperture Management Protocol provides an interface that
+  UEFI drivers/modules can use to enable/disable the sharing of buffers with 
the
+  Host. The protocol also tracks open apertures and ensures they are shut on
+  ExitBootServices.
+
+  Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - RAMP  - Realm Aperture Management Protocol
+**/
+
+#ifndef REALM_APERTURE_MANAGEMENT_PROTOCOL_H_
+#define REALM_APERTURE_MANAGEMENT_PROTOCOL_H_
+
+/** This macro defines the Realm Aperture Management Protocol GUID.
+
+  GUID: {585C00BE-CF7C-4DB8-8AA2-490D67F5F6E6}
+*/
+#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_GUID     \
+  { 0x585c00be, 0xcf7c, 0x4db8,                         \
+    { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 }   \
+  };
+
+/** This macro defines the Realm Aperture Management Protocol Revision.
+*/
+#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION  0x00010000
+
+#pragma pack(1)
+
+/** Enables sharing of the memory buffers with the host.
+
+  @param [in]  Memory             Pointer to the page start address.
+  @param [in]  Pages              Number of pages to share.
+  @param [out] ApertureReference  Reference to the opened aperture.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_OUT_OF_RESOURCES    Memory allocation failed.
+  @retval EFI_ACCESS_DENIED       Aperture already open over memory region.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE)(
+  IN  CONST EFI_PHYSICAL_ADDRESS                    Memory,
+  IN  CONST UINTN                                   Pages,
+  OUT       EFI_HANDLE                      *CONST ApertureReference
+  );
+
+/** Disables the sharing of the buffers.
+
+  @param [in] ApertureReference   Reference to the aperture for closing.
+
+  @retval EFI_SUCCESS             The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_NOT_FOUND           The required buffer information is not found.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE)(
+  IN  CONST EFI_HANDLE                              ApertureReference
+  );
+
+/** A structure describing the interface provided by the Realm Aperture
+    Management Protocol.
+*/
+typedef struct RealmApertureManagementProtocol {
+  /// The Realm Aperture Management Protocol revision.
+  UINT64                                                     Revision;
+
+  /// Shares Realm Pages(s) with the Host.
+  EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE     OpenAperture;
+
+  /// Makes the Realm Pages(s) private to the Realm.
+  EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE    CloseAperture;
+} EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL;
+
+/** The Realm Aperture Management Protocol GUID.
+*/
+extern EFI_GUID  gEfiRealmApertureManagementProtocolGuid;
+
+#pragma pack()
+
+#endif // REALM_APERTURE_MANAGEMENT_PROTOCOL_H_
diff --git 
a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c
 
b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c
new file mode 100644
index 
0000000000000000000000000000000000000000..991054d47b10b45ed5c211827e795d88f8942c02
--- /dev/null
+++ 
b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c
@@ -0,0 +1,658 @@
+/** @file
+  Realm Aperture Management Protocol Dxe
+
+  Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Glossary:
+    - IPA   - Intermediate Physical Address
+    - RAMP  - Realm Aperture Management Protocol
+    - RIPAS - Realm IPA state
+    - RSI   - Realm Service Interface
+**/
+
+#include <Base.h>
+#include <Library/ArmCcaLib.h>
+#include <Library/ArmCcaRsiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/RealmApertureManagementProtocol.h>
+#include <Protocol/ResetNotification.h>
+
+/**
+  A macro defining the signature for the aperture information structure.
+*/
+#define APERTURE_INFO_SIG  SIGNATURE_64 ('A', 'P', 'E', 'R', 'T', 'U', 'R', 
'E')
+
+/**
+  A structure describing the aperture.
+*/
+typedef struct {
+  /// Signature for identifying this structure.
+  UINT64                  Signature;
+
+  /// The linked list entry.
+  LIST_ENTRY              Link;
+
+  /// The base address for the start of the aperture.
+  EFI_PHYSICAL_ADDRESS    BaseAddress;
+
+  /// The number of pages covered by the aperture.
+  UINTN                   Pages;
+
+  /// The bit mask of attributes for the memory region. The
+  /// bit mask of available attributes is defined in GetMemoryMap().
+  UINT64                  MemoryAttributes;
+
+  /// The RIPAS for the aperture.
+  RIPAS                   Ripas;
+} APERTURE_INFO;
+
+/**
+  List of the APERTURE_INFO structures that have been set up by OpenAperture()
+  and not yet torn down by CloseAperture(). The list represents the full set
+  of open apertures currently in effect.
+*/
+STATIC
+LIST_ENTRY  mApertureInfos = INITIALIZE_LIST_HEAD_VARIABLE (mApertureInfos);
+
+/**
+  A local variable to store the IPA width of the Realm. The IPA width
+  of the Realm is required to configure the protection attribute of
+  memory regions.
+*/
+STATIC UINT64  mIpaWidth;
+
+/** Checks if an open aperture is overlapping the memory region.
+
+  @param [in]  MemStart           Pointer to the page start address.
+  @param [in]  Pages              Number of pages to share.
+
+  @retval TRUE  If memory region overlaps an open aperture.
+  @retval FALSE Memory region does not overlap any open apertures.
+**/
+STATIC
+BOOLEAN
+EFIAPI
+IsApertureOverlapping (
+  IN  CONST EFI_PHYSICAL_ADDRESS  MemStart,
+  IN  CONST UINTN                 Pages
+  )
+{
+  LIST_ENTRY            *Node;
+  LIST_ENTRY            *NextNode;
+  APERTURE_INFO         *ApertureInfo;
+  EFI_PHYSICAL_ADDRESS  MemEnd;
+  EFI_PHYSICAL_ADDRESS  ApertureStart;
+  EFI_PHYSICAL_ADDRESS  ApertureEnd;
+
+  MemEnd = MemStart + (EFI_PAGE_SIZE * Pages) - 1;
+
+  // All drivers that had opened the apertures have halted their respective
+  // controllers by now; close all the apertures.
+  for (
+       Node = GetFirstNode (&mApertureInfos);
+       Node != &mApertureInfos;
+       Node = NextNode
+       )
+  {
+    NextNode      = GetNextNode (&mApertureInfos, Node);
+    ApertureInfo  = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG);
+    ApertureStart = ApertureInfo->BaseAddress;
+    ApertureEnd   = ApertureStart + (EFI_PAGE_SIZE * ApertureInfo->Pages) - 1;
+
+    if (((ApertureStart >= MemStart) && (ApertureStart <= MemEnd)) ||
+        ((ApertureEnd >= MemStart) && (ApertureEnd <= MemEnd))     ||
+        ((MemStart >= ApertureStart) && (MemStart <= ApertureEnd)) ||
+        ((MemEnd >= ApertureStart) && (MemEnd <= ApertureEnd)))
+    {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/** Enables sharing of the memory buffers with the host.
+
+  @param [in]  Memory             Pointer to the page start address.
+  @param [in]  Pages              Number of pages to share.
+  @param [out] ApertureReference  Reference to the opened aperture.
+
+  @retval EFI_SUCCESS             Success.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_OUT_OF_RESOURCES    Memory allocation failed.
+  @retval EFI_ACCESS_DENIED       Aperture already open over memory region.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RampOpenAperture (
+  IN  CONST EFI_PHYSICAL_ADDRESS                    Memory,
+  IN  CONST UINTN                                   Pages,
+  OUT       EFI_HANDLE                      *CONST  ApertureReference
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_STATUS                       Status1;
+  APERTURE_INFO                    *ApertInfo;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  GcdDescriptor;
+  EFI_PHYSICAL_ADDRESS             MemRangeAddr;
+  UINTN                            Index;
+
+  if ((Memory == 0) ||
+      (Pages == 0)  ||
+      (ApertureReference == NULL) ||
+      ((Memory & (EFI_PAGE_SIZE - 1)) != 0))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // The pages size must be aligned to the Realm Granule size.
+  STATIC_ASSERT ((EFI_PAGE_SIZE & (REALM_GRANULE_SIZE - 1)) == 0);
+
+  // Checks if we already have an open aperture that overlaps the
+  // memory region. If so return the request as invalid.
+  if (IsApertureOverlapping (Memory, Pages)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MemRangeAddr = Memory;
+  for (Index = 0; Index < Pages; Index++) {
+    Status = gDS->GetMemorySpaceDescriptor (MemRangeAddr, &GcdDescriptor);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: Memory = 0x%lx, MemType = %a\n",
+      __func__,
+      MemRangeAddr,
+      ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) ?
+      "Runtime Services Memory" : "Boot Services Memory"
+      ));
+
+    // We currently do not have a usecase where we would want to open apertures
+    // for runtime services memory
+    if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) 
{
+      return EFI_UNSUPPORTED;
+    }
+
+    MemRangeAddr += EFI_PAGE_SIZE;
+  } // for
+
+  Status = ArmCcaSetMemoryProtectAttribute (
+             Memory,
+             EFI_PAGES_TO_SIZE (Pages),
+             mIpaWidth,
+             TRUE
+             );
+  if (RETURN_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: Failed to update page tables for Protected EMPTY page mapping, "
+      "Address = %p, Pages = 0x%lx, Status = %r\n",
+      Memory,
+      Pages,
+      Status
+      ));
+    return Status;
+  }
+
+  // Allocate a APERTURE_INFO structure to remember the apertures opened.
+  ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO));
+  if (ApertInfo == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto error_handler1;
+  }
+
+  InitializeListHead (&ApertInfo->Link);
+  ApertInfo->Signature        = APERTURE_INFO_SIG;
+  ApertInfo->BaseAddress      = Memory;
+  ApertInfo->Pages            = Pages;
+  ApertInfo->MemoryAttributes = GcdDescriptor.Attributes;
+  ApertInfo->Ripas            = RipasEmpty;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, "
+    "MemoryAttributes = 0x%x, Ripas = 0x%x\n",
+    __func__,
+    ApertInfo,
+    ApertInfo->BaseAddress,
+    ApertInfo->Pages,
+    ApertInfo->MemoryAttributes,
+    ApertInfo->Ripas
+    ));
+
+  // Set the Realm IPA state to Empty to open the Aperture
+  Status = RsiSetIpaState (
+             (UINT64 *)Memory,
+             (Pages * EFI_PAGE_SIZE),
+             RipasEmpty
+             );
+  if (RETURN_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: RSI Set IPA State failed, Address = %p, Pages = 0x%lx, "
+      "Status = %r\n",
+      Memory,
+      Pages,
+      Status
+      ));
+    goto error_handler;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "SUCCESS: RSI Set IPA State complete, Address = %p, Pages = 0x%lx, "
+    "Status = %r\n",
+    Memory,
+    Pages,
+    Status
+    ));
+
+  InsertHeadList (&mApertureInfos, &ApertInfo->Link);
+  *ApertureReference = (EFI_HANDLE *)&ApertInfo->Link;
+
+  return Status;
+
+error_handler:
+
+  FreePool (ApertInfo);
+
+error_handler1:
+  Status1 = ArmCcaSetMemoryProtectAttribute (
+              Memory,
+              EFI_PAGES_TO_SIZE (Pages),
+              mIpaWidth,
+              FALSE
+              );
+  if (RETURN_ERROR (Status1)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: Failed to update page tables to Protected page mapping, "
+      "Address = %p, Pages = 0x%lx, Status = %r\n",
+      Memory,
+      Pages,
+      Status1
+      ));
+  }
+
+  *ApertureReference = NULL;
+  // return the first error code
+  return Status;
+}
+
+/** Disables the sharing of the buffers.
+
+  @param [in] ApertureReference   Reference to the aperture for closing.
+
+  @retval EFI_SUCCESS             The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+  @retval EFI_NOT_FOUND           The required buffer information is not found.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+RampCloseAperture (
+  IN  CONST EFI_HANDLE  ApertureReference
+  )
+{
+  EFI_STATUS     Status;
+  APERTURE_INFO  *ApertInfo;
+
+  if (ApertureReference == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ApertInfo = NULL;
+  ApertInfo = CR (ApertureReference, APERTURE_INFO, Link, APERTURE_INFO_SIG);
+  if (ApertInfo == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, "
+    "MemoryAttributes = 0x%x, Ripas = 0x%x\n",
+    __func__,
+    ApertInfo,
+    ApertInfo->BaseAddress,
+    ApertInfo->Pages,
+    ApertInfo->MemoryAttributes,
+    ApertInfo->Ripas
+    ));
+
+  // Set the Realm IPA state to RAM to close the Aperture
+  Status = RsiSetIpaState (
+             (UINT64 *)ApertInfo->BaseAddress,
+             (ApertInfo->Pages * EFI_PAGE_SIZE),
+             RipasRam
+             );
+  if (RETURN_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: RSI Set IPA State failed, Address = %p, Pages = 0x%lx, "
+      "Status = %r\n",
+      ApertInfo->BaseAddress,
+      ApertInfo->Pages,
+      Status
+      ));
+    return Status;
+  }
+
+  Status = ArmCcaSetMemoryProtectAttribute (
+             ApertInfo->BaseAddress,
+             EFI_PAGES_TO_SIZE (ApertInfo->Pages),
+             mIpaWidth,
+             FALSE
+             );
+  if (RETURN_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: Failed to update page tables for Protected RAM page mapping,"
+      "Address = %p, Pages = 0x%lx, Status = %r\n",
+      ApertInfo->BaseAddress,
+      ApertInfo->Pages,
+      Status
+      ));
+  }
+
+  RemoveEntryList (&ApertInfo->Link);
+  FreePool (ApertInfo);
+
+  return Status;
+}
+
+/** Closes all open apertures.
+
+**/
+STATIC
+VOID
+EFIAPI
+RampCloseAllApertures (
+  VOID
+  )
+{
+  LIST_ENTRY     *Node;
+  LIST_ENTRY     *NextNode;
+  APERTURE_INFO  *ApertureInfo;
+
+  // All drivers that had opened the apertures have halted their respective
+  // controllers by now; close all the apertures.
+  for (
+       Node = GetFirstNode (&mApertureInfos);
+       Node != &mApertureInfos;
+       Node = NextNode
+       )
+  {
+    NextNode     = GetNextNode (&mApertureInfos, Node);
+    ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG);
+    RampCloseAperture (&ApertureInfo->Link);
+  }
+}
+
+/**
+  Notification function that is queued after the notification functions of all
+  events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group.
+
+  This function invokes the closing of all open apertures.
+
+  @param[in] Event    Event whose notification function is being invoked. Event
+                      is permitted to request the queueing of this function
+                      only at TPL_CALLBACK task priority level.
+
+  @param[in] Context  Ignored.
+**/
+STATIC
+VOID
+EFIAPI
+OnRampExitBootServicesEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  RampCloseAllApertures ();
+}
+
+/**
+  Notification function that is queued when gBS->ExitBootServices() signals the
+  EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another
+  event, received as Context, and returns.
+
+  Signaling an event in this context is safe. The UEFI spec allows
+  gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not
+  listed, hence memory is not allocated.
+
+  @param[in] Event          Event whose notification function is being invoked.
+                            Event is permitted to request the queueing of this
+                            function at TPL_CALLBACK or TPL_NOTIFY task
+                            priority level.
+
+  @param[in] EventToSignal  Identifies the EFI_EVENT to signal. EventToSignal
+                            is permitted to request the queueing of its
+                            notification function only at TPL_CALLBACK level.
+**/
+STATIC
+VOID
+EFIAPI
+RampExitBootServices (
+  IN EFI_EVENT  Event,
+  IN VOID       *EventToSignal
+  )
+{
+  // (1) The NotifyFunctions of all the events in
+  //     EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
+  //     RampExitBootServices() is entered.
+  //
+  // (2) RampExitBootServices() is executing minimally at TPL_CALLBACK.
+  //
+  // (3) RampExitBootServices() has been queued in unspecified order relative
+  //      to the NotifyFunctions of all the other events in
+  //     EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
+  //     Event's.
+  //
+  // Consequences:
+  //
+  // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
+  //   queued at TPL_CALLBACK may be invoked after RampExitBootServices()
+  //   returns.
+  //
+  // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
+  //   queued at TPL_NOTIFY may be invoked after RampExitBootServices()
+  //   returns; plus *all* NotifyFunctions queued at TPL_CALLBACK will be
+  //   invoked strictly after all NotifyFunctions queued at TPL_NOTIFY,
+  //   including RampExitBootServices(), have been invoked.
+  //
+  // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
+  //   queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
+  //   events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.
+  gBS->SignalEvent (EventToSignal);
+}
+
+/** A structure describing the Realm Aperture Management protocol.
+*/
+STATIC
+CONST
+EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL  Ramp = {
+  EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION,
+  RampOpenAperture,
+  RampCloseAperture
+};
+
+/**
+  This routine is called to close all apertures before system reset.
+
+  @param[in]  ResetType    The type of reset to perform.
+  @param[in]  ResetStatus  The status code for the reset.
+  @param[in]  DataSize     The size, in bytes, of ResetData.
+  @param[in]  ResetData    For a ResetType of EfiResetCold, EfiResetWarm, or
+                           EfiResetShutdown the data buffer starts with a Null-
+                           terminated string, optionally followed by additional
+                           binary data. The string is a description that the
+                           caller may use to further indicate the reason for
+                           the system reset. ResetData is only valid if
+                           ResetStatus is something other than EFI_SUCCESS
+                           unless the ResetType is EfiResetPlatformSpecific
+                           where a minimum amount of ResetData is always
+                           required.
+                           For a ResetType of EfiResetPlatformSpecific the data
+                           buffer also starts with a Null-terminated string
+                           that is followed by an EFI_GUID that describes the
+                           specific type of reset to perform.
+**/
+VOID
+EFIAPI
+OnResetEvent (
+  IN EFI_RESET_TYPE  ResetType,
+  IN EFI_STATUS      ResetStatus,
+  IN UINTN           DataSize,
+  IN VOID            *ResetData OPTIONAL
+  )
+{
+  RampCloseAllApertures ();
+}
+
+/**
+  Hook the system reset to close all apertures.
+
+  @param[in]  Event     Event whose notification function is being invoked
+  @param[in]  Context   Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+OnResetNotificationInstall (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_RESET_NOTIFICATION_PROTOCOL  *ResetNotify;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiResetNotificationProtocolGuid,
+                  NULL,
+                  (VOID **)&ResetNotify
+                  );
+  if (!EFI_ERROR (Status)) {
+    Status = ResetNotify->RegisterResetNotify (ResetNotify, OnResetEvent);
+    ASSERT_EFI_ERROR (Status);
+    DEBUG ((DEBUG_INFO, "RAMP: Hook system reset to close all apertures.\n"));
+    gBS->CloseEvent (Event);
+  }
+}
+
+/** Entry point for Realm Aperture Management Protocol Dxe
+
+  @param [in]  ImageHandle  Handle for this image.
+  @param [in]  SystemTable  Pointer to the EFI system table.
+
+  @retval EFI_SUCCESS             When executing in a Realm the RAMP was
+                                  installed successfully.
+                                  When execution context is not a Realm, this
+                                  function returns success indicating nothing
+                                  needs to be done and allow other modules to
+                                  run.
+  @retval EFI_OUT_OF_RESOURCES    There was not enough memory to install the
+                                  protocols.
+  @retval EFI_INVALID_PARAMETER   A parameter is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+RealmApertureManagementProtocolDxeInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  Handle;
+  EFI_EVENT   CloseAllAperturesEvent;
+  EFI_EVENT   ExitBootEvent;
+  VOID        *Registration;
+
+  // When the execution context is a Realm, install the Realm Aperture
+  // Management protocol otherwise return success so that other modules
+  // can run.
+  if (!IsRealm ()) {
+    return EFI_SUCCESS;
+  }
+
+  // Retrieve the IPA Width of the Realm for subsequent use to configure
+  // the protection attribute of memory regions.
+  Status = GetIpaWidth (&mIpaWidth);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ERROR: Failed to get Ipa Width, Status = %r\n",
+      Status
+      ));
+    ASSERT (0);
+    return Status;
+  }
+
+  /*
+    Create the "late" event whose notification function will close all
+    apertures.
+  */
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,            // Type
+                  TPL_CALLBACK,                 // NotifyTpl
+                  OnRampExitBootServicesEvent,  // NotifyFunction
+                  NULL,                         // NotifyContext
+                  &CloseAllAperturesEvent       // Event
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  /*
+    Create the event whose notification function will be queued by
+    gBS->ExitBootServices() and will signal the event created above.
+  */
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type
+                  TPL_CALLBACK,                  // NotifyTpl
+                  RampExitBootServices,          // NotifyFunction
+                  CloseAllAperturesEvent,        // NotifyContext
+                  &ExitBootEvent                 // Event
+                  );
+  if (EFI_ERROR (Status)) {
+    goto error_handler1;
+  }
+
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEfiRealmApertureManagementProtocolGuid,
+                  &Ramp,
+                  NULL
+                  );
+  if (!EFI_ERROR (Status)) {
+    // RAMP Protocol installed successfully
+    // Hook the system reset to close all apertures.
+    EfiCreateProtocolNotifyEvent (
+      &gEfiResetNotificationProtocolGuid,
+      TPL_CALLBACK,
+      OnResetNotificationInstall,
+      NULL,
+      &Registration
+      );
+    return Status;
+  }
+
+  // cleanup on error
+  gBS->CloseEvent (ExitBootEvent);
+
+error_handler1:
+  gBS->CloseEvent (CloseAllAperturesEvent);
+  return Status;
+}
diff --git 
a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf
 
b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf
new file mode 100644
index 
0000000000000000000000000000000000000000..2e3021b82bd75b7f41dc9427117a8394dfde2e68
--- /dev/null
+++ 
b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf
@@ -0,0 +1,48 @@
+## @file
+#  Module to manage the sharing of buffers in a Realm with the Host.
+#
+#  Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = RealmApertureManagementProtocolDxe
+  FILE_GUID                      = CEC2F7D5-2564-46D4-A23F-501623F7F56A
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = RealmApertureManagementProtocolDxeInitialize
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = AARCH64
+#
+
+[Sources]
+  RealmApertureManagementProtocolDxe.c
+
+[Packages]
+  ArmVirtPkg/ArmVirtPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  ArmCcaLib
+  ArmCcaRsiLib
+  BaseLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  PrintLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEfiRealmApertureManagementProtocolGuid         ## SOMETIME_PRODUCES
+  gEfiResetNotificationProtocolGuid               ## CONSUMES
+
+[Depex]
+  TRUE
-- 
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117697): https://edk2.groups.io/g/devel/message/117697
Mute This Topic: https://groups.io/mt/105483438/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-



Reply via email to