]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLibProtocol.c
UnitTestFrameworkPkg: Add UnitTestUefiBootServicesTableLib
[mirror_edk2.git] / UnitTestFrameworkPkg / Library / UnitTestUefiBootServicesTableLib / UnitTestUefiBootServicesTableLibProtocol.c
diff --git a/UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLibProtocol.c b/UnitTestFrameworkPkg/Library/UnitTestUefiBootServicesTableLib/UnitTestUefiBootServicesTableLibProtocol.c
new file mode 100644 (file)
index 0000000..437082d
--- /dev/null
@@ -0,0 +1,1650 @@
+/** @file\r
+  Implementation of protocol related services in the UEFI Boot Services table for use in unit tests.\r
+\r
+Copyright (c) Microsoft Corporation\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "UnitTestUefiBootServicesTableLibProtocol.h"\r
+\r
+STATIC LIST_ENTRY  mProtocolDatabase       = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);\r
+STATIC LIST_ENTRY  gHandleList             = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);\r
+STATIC UINT64      gHandleDatabaseKey      = 0;\r
+STATIC UINTN       mEfiLocateHandleRequest = 0;\r
+\r
+//\r
+// Helper Functions\r
+//\r
+\r
+/**\r
+  Check whether a handle is a valid EFI_HANDLE\r
+\r
+  @param  UserHandle             The handle to check\r
+\r
+  @retval EFI_INVALID_PARAMETER  The handle is NULL or not a valid EFI_HANDLE.\r
+  @retval EFI_SUCCESS            The handle is valid EFI_HANDLE.\r
+\r
+**/\r
+EFI_STATUS\r
+UnitTestValidateHandle (\r
+  IN  EFI_HANDLE  UserHandle\r
+  )\r
+{\r
+  IHANDLE     *Handle;\r
+  LIST_ENTRY  *Link;\r
+\r
+  if (UserHandle == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (Link = gHandleList.BackLink; Link != &gHandleList; Link = Link->BackLink) {\r
+    Handle = CR (Link, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);\r
+    if (Handle == (IHANDLE *)UserHandle) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+/**\r
+  Finds the protocol entry for the requested protocol.\r
+\r
+  @param  Protocol               The ID of the protocol\r
+  @param  Create                 Create a new entry if not found\r
+\r
+  @return Protocol entry\r
+\r
+**/\r
+PROTOCOL_ENTRY  *\r
+UnitTestFindProtocolEntry (\r
+  IN EFI_GUID  *Protocol,\r
+  IN BOOLEAN   Create\r
+  )\r
+{\r
+  LIST_ENTRY      *Link;\r
+  PROTOCOL_ENTRY  *Item;\r
+  PROTOCOL_ENTRY  *ProtEntry;\r
+\r
+  //\r
+  // Search the database for the matching GUID\r
+  //\r
+\r
+  ProtEntry = NULL;\r
+  for (Link = mProtocolDatabase.ForwardLink;\r
+       Link != &mProtocolDatabase;\r
+       Link = Link->ForwardLink)\r
+  {\r
+    Item = CR (Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);\r
+    if (CompareGuid (&Item->ProtocolID, Protocol)) {\r
+      //\r
+      // This is the protocol entry\r
+      //\r
+\r
+      ProtEntry = Item;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the protocol entry was not found and Create is TRUE, then\r
+  // allocate a new entry\r
+  //\r
+  if ((ProtEntry == NULL) && Create) {\r
+    ProtEntry = AllocatePool (sizeof (PROTOCOL_ENTRY));\r
+\r
+    if (ProtEntry != NULL) {\r
+      //\r
+      // Initialize new protocol entry structure\r
+      //\r
+      ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;\r
+      CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);\r
+      InitializeListHead (&ProtEntry->Protocols);\r
+      InitializeListHead (&ProtEntry->Notify);\r
+\r
+      //\r
+      // Add it to protocol database\r
+      //\r
+      InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);\r
+    }\r
+  }\r
+\r
+  return ProtEntry;\r
+}\r
+\r
+/**\r
+  Finds the protocol instance for the requested handle and protocol.\r
+  Note: This function doesn't do parameters checking, it's caller's responsibility\r
+  to pass in valid parameters.\r
+\r
+  @param  Handle                 The handle to search the protocol on\r
+  @param  Protocol               GUID of the protocol\r
+  @param  Interface              The interface for the protocol being searched\r
+\r
+  @return Protocol instance (NULL: Not found)\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+UnitTestFindProtocolInterface (\r
+  IN IHANDLE   *Handle,\r
+  IN EFI_GUID  *Protocol,\r
+  IN VOID      *Interface\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Prot = NULL;\r
+\r
+  //\r
+  // Lookup the protocol entry for this protocol ID\r
+  //\r
+\r
+  ProtEntry = UnitTestFindProtocolEntry (Protocol, FALSE);\r
+  if (ProtEntry != NULL) {\r
+    //\r
+    // Look at each protocol interface for any matches\r
+    //\r
+    for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+      //\r
+      // If this protocol interface matches, remove it\r
+      //\r
+      Prot = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+      if ((Prot->Interface == Interface) && (Prot->Protocol == ProtEntry)) {\r
+        break;\r
+      }\r
+\r
+      Prot = NULL;\r
+    }\r
+  }\r
+\r
+  return Prot;\r
+}\r
+\r
+/**\r
+  Signal event for every protocol in protocol entry.\r
+\r
+  @param  ProtEntry              Protocol entry\r
+\r
+**/\r
+VOID\r
+UnitTestNotifyProtocolEntry (\r
+  IN PROTOCOL_ENTRY  *ProtEntry\r
+  )\r
+{\r
+  PROTOCOL_NOTIFY  *ProtNotify;\r
+  LIST_ENTRY       *Link;\r
+\r
+  for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {\r
+    ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+    UnitTestSignalEvent (ProtNotify->Event);\r
+  }\r
+}\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for all handles.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+UnitTestGetNextLocateAllHandles (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT VOID                **Interface\r
+  )\r
+{\r
+  IHANDLE  *Handle;\r
+\r
+  //\r
+  // Next handle\r
+  //\r
+  Position->Position = Position->Position->ForwardLink;\r
+\r
+  //\r
+  // If not at the end of the list, get the handle\r
+  //\r
+  Handle     = NULL;\r
+  *Interface = NULL;\r
+  if (Position->Position != &gHandleList) {\r
+    Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);\r
+  }\r
+\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for register protocol\r
+  notifies.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+UnitTestGetNextLocateByRegisterNotify (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT VOID                **Interface\r
+  )\r
+{\r
+  IHANDLE             *Handle;\r
+  PROTOCOL_NOTIFY     *ProtNotify;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Handle     = NULL;\r
+  *Interface = NULL;\r
+  ProtNotify = Position->SearchKey;\r
+\r
+  //\r
+  // If this is the first request, get the next handle\r
+  //\r
+  if (ProtNotify != NULL) {\r
+    ASSERT (ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);\r
+    Position->SearchKey = NULL;\r
+\r
+    //\r
+    // If not at the end of the list, get the next handle\r
+    //\r
+    Link = ProtNotify->Position->ForwardLink;\r
+    if (Link != &ProtNotify->Protocol->Protocols) {\r
+      Prot       = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+      Handle     = Prot->Handle;\r
+      *Interface = Prot->Interface;\r
+    }\r
+  }\r
+\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Routine to get the next Handle, when you are searching for a given protocol.\r
+\r
+  @param  Position               Information about which Handle to seach for.\r
+  @param  Interface              Return the interface structure for the matching\r
+                                 protocol.\r
+\r
+  @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+          Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+UnitTestGetNextLocateByProtocol (\r
+  IN OUT LOCATE_POSITION  *Position,\r
+  OUT VOID                **Interface\r
+  )\r
+{\r
+  IHANDLE             *Handle;\r
+  LIST_ENTRY          *Link;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+\r
+  Handle     = NULL;\r
+  *Interface = NULL;\r
+  for ( ; ;) {\r
+    //\r
+    // Next entry\r
+    //\r
+    Link               = Position->Position->ForwardLink;\r
+    Position->Position = Link;\r
+\r
+    //\r
+    // If not at the end, return the handle\r
+    //\r
+    if (Link == &Position->ProtEntry->Protocols) {\r
+      Handle = NULL;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Get the handle\r
+    //\r
+    Prot       = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+    Handle     = Prot->Handle;\r
+    *Interface = Prot->Interface;\r
+\r
+    //\r
+    // If this handle has not been returned this request, then\r
+    // return it now\r
+    //\r
+    if (Handle->LocateRequest != mEfiLocateHandleRequest) {\r
+      Handle->LocateRequest = mEfiLocateHandleRequest;\r
+      break;\r
+    }\r
+  }\r
+\r
+  return Handle;\r
+}\r
+\r
+/**\r
+  Attempts to disconnect all drivers that are using the protocol interface being queried.\r
+  If failed, reconnect all drivers disconnected.\r
+  Note: This function doesn't do parameters checking, it's caller's responsibility\r
+  to pass in valid parameters.\r
+\r
+  @param  UserHandle             The handle on which the protocol is installed\r
+  @param  Prot                   The protocol to disconnect drivers from\r
+\r
+  @retval EFI_SUCCESS            Drivers using the protocol interface are all\r
+                                 disconnected\r
+  @retval EFI_ACCESS_DENIED      Failed to disconnect one or all of the drivers\r
+\r
+**/\r
+EFI_STATUS\r
+UnitTestDisconnectControllersUsingProtocolInterface (\r
+  IN EFI_HANDLE          UserHandle,\r
+  IN PROTOCOL_INTERFACE  *Prot\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  BOOLEAN             ItemFound;\r
+  LIST_ENTRY          *Link;\r
+  OPEN_PROTOCOL_DATA  *OpenData;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  // Attempt to disconnect all drivers from this protocol interface\r
+  //\r
+  do {\r
+    ItemFound = FALSE;\r
+    for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {\r
+      OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
+      if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+        Status = UnitTestDisconnectController (UserHandle, OpenData->AgentHandle, NULL);\r
+        if (!EFI_ERROR (Status)) {\r
+          ItemFound = TRUE;\r
+        }\r
+\r
+        break;\r
+      }\r
+    }\r
+  } while (ItemFound);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Attempt to remove BY_HANDLE_PROTOCOL and GET_PROTOCOL and TEST_PROTOCOL Open List items\r
+    //\r
+    for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList;) {\r
+      OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
+      if ((OpenData->Attributes &\r
+           (EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | EFI_OPEN_PROTOCOL_GET_PROTOCOL | EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) != 0)\r
+      {\r
+        Link = RemoveEntryList (&OpenData->Link);\r
+        Prot->OpenListCount--;\r
+        FreePool (OpenData);\r
+      } else {\r
+        Link = Link->ForwardLink;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // If there are errors or still has open items in the list, then reconnect all the drivers and return an error\r
+  //\r
+  if (EFI_ERROR (Status) || (Prot->OpenListCount > 0)) {\r
+    UnitTestConnectController (UserHandle, NULL, NULL, TRUE);\r
+    Status = EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Removes Protocol from the protocol list (but not the handle list).\r
+\r
+  @param  Handle                 The handle to remove protocol on.\r
+  @param  Protocol               GUID of the protocol to be moved\r
+  @param  Interface              The interface of the protocol\r
+\r
+  @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+UnitTestRemoveInterfaceFromProtocol (\r
+  IN IHANDLE   *Handle,\r
+  IN EFI_GUID  *Protocol,\r
+  IN VOID      *Interface\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_NOTIFY     *ProtNotify;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Prot = UnitTestFindProtocolInterface (Handle, Protocol, Interface);\r
+  if (Prot != NULL) {\r
+    ProtEntry = Prot->Protocol;\r
+\r
+    //\r
+    // If there's a protocol notify location pointing to this entry, back it up one\r
+    //\r
+    for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) {\r
+      ProtNotify = CR (Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+\r
+      if (ProtNotify->Position == &Prot->ByProtocol) {\r
+        ProtNotify->Position = Prot->ByProtocol.BackLink;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Remove the protocol interface entry\r
+    //\r
+    RemoveEntryList (&Prot->ByProtocol);\r
+  }\r
+\r
+  return Prot;\r
+}\r
+\r
+//\r
+// Boot Services Function Implementation\r
+//\r
+\r
+/**\r
+  Locate a certain GUID protocol interface in a Handle's protocols.\r
+\r
+  @param  UserHandle             The handle to obtain the protocol interface on\r
+  @param  Protocol               The GUID of the protocol\r
+\r
+  @return The requested protocol interface for the handle\r
+\r
+**/\r
+PROTOCOL_INTERFACE  *\r
+UnitTestGetProtocolInterface (\r
+  IN  EFI_HANDLE  UserHandle,\r
+  IN  EFI_GUID    *Protocol\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  IHANDLE             *Handle;\r
+  LIST_ENTRY          *Link;\r
+\r
+  Status = UnitTestValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Handle = (IHANDLE *)UserHandle;\r
+\r
+  //\r
+  // Look at each protocol interface for a match\r
+  //\r
+  for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+    Prot      = CR (Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+    ProtEntry = Prot->Protocol;\r
+    if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {\r
+      return Prot;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Installs a protocol interface into the boot services environment.\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+  @param  Notify                 indicates whether notify the notification list\r
+                                 for this protocol\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate\r
+  @retval EFI_SUCCESS            Protocol interface successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+UnitTestInstallProtocolInterfaceNotify (\r
+  IN OUT EFI_HANDLE      *UserHandle,\r
+  IN EFI_GUID            *Protocol,\r
+  IN EFI_INTERFACE_TYPE  InterfaceType,\r
+  IN VOID                *Interface,\r
+  IN BOOLEAN             Notify\r
+  )\r
+{\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  PROTOCOL_ENTRY      *ProtEntry;\r
+  IHANDLE             *Handle;\r
+  EFI_STATUS          Status;\r
+  VOID                *ExistingInterface;\r
+\r
+  //\r
+  // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.\r
+  // Also added check for invalid UserHandle and Protocol pointers.\r
+  //\r
+  if ((UserHandle == NULL) || (Protocol == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InterfaceType != EFI_NATIVE_INTERFACE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Print debug message\r
+  //\r
+  UT_LOG_INFO ("InstallProtocolInterface: %g %p\n", Protocol, Interface);\r
+\r
+  Status = EFI_OUT_OF_RESOURCES;\r
+  Prot   = NULL;\r
+  Handle = NULL;\r
+\r
+  if (*UserHandle != NULL) {\r
+    Status = UnitTestHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);\r
+    if (!EFI_ERROR (Status)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Lookup the Protocol Entry for the requested protocol\r
+  //\r
+  ProtEntry = UnitTestFindProtocolEntry (Protocol, TRUE);\r
+  if (ProtEntry == NULL) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Allocate a new protocol interface structure\r
+  //\r
+  Prot = AllocateZeroPool (sizeof (PROTOCOL_INTERFACE));\r
+  if (Prot == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // If caller didn't supply a handle, allocate a new one\r
+  //\r
+  Handle = (IHANDLE *)*UserHandle;\r
+  if (Handle == NULL) {\r
+    Handle = AllocateZeroPool (sizeof (IHANDLE));\r
+    if (Handle == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Initialize new handler structure\r
+    //\r
+    Handle->Signature = EFI_HANDLE_SIGNATURE;\r
+    InitializeListHead (&Handle->Protocols);\r
+\r
+    //\r
+    // Initialize the Key to show that the handle has been created/modified\r
+    //\r
+    gHandleDatabaseKey++;\r
+    Handle->Key = gHandleDatabaseKey;\r
+\r
+    //\r
+    // Add this handle to the list global list of all handles\r
+    // in the system\r
+    //\r
+    InsertTailList (&gHandleList, &Handle->AllHandles);\r
+  } else {\r
+    Status =  UnitTestValidateHandle (Handle);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: input handle at 0x%x is invalid\n", Handle));\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Each interface that is added must be unique\r
+  //\r
+  ASSERT (UnitTestFindProtocolInterface (Handle, Protocol, Interface) == NULL);\r
+\r
+  //\r
+  // Initialize the protocol interface structure\r
+  //\r
+  Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;\r
+  Prot->Handle    = Handle;\r
+  Prot->Protocol  = ProtEntry;\r
+  Prot->Interface = Interface;\r
+\r
+  //\r
+  // Initialize OpenProtocol Data base\r
+  //\r
+  InitializeListHead (&Prot->OpenList);\r
+  Prot->OpenListCount = 0;\r
+\r
+  //\r
+  // Add this protocol interface to the head of the supported\r
+  // protocol list for this handle\r
+  //\r
+  InsertHeadList (&Handle->Protocols, &Prot->Link);\r
+\r
+  //\r
+  // Add this protocol interface to the tail of the\r
+  // protocol entry\r
+  //\r
+  InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
+\r
+  //\r
+  // Notify the notification list for this protocol\r
+  //\r
+  if (Notify) {\r
+    UnitTestNotifyProtocolEntry (ProtEntry);\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Return the new handle back to the caller\r
+    //\r
+    *UserHandle = Handle;\r
+  } else {\r
+    //\r
+    // There was an error, clean up\r
+    //\r
+    if (Prot != NULL) {\r
+      UnitTestFreePool (Prot);\r
+    }\r
+\r
+    DEBUG ((DEBUG_ERROR, "InstallProtocolInterface: %g %p failed with %r\n", Protocol, Interface, Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wrapper function to UnitTestInstallProtocolInterfaceNotify.  This is the public API which\r
+  Calls the private one which contains a BOOLEAN parameter for notifications\r
+\r
+  @param  UserHandle             The handle to install the protocol handler on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  Protocol               The protocol to add to the handle\r
+  @param  InterfaceType          Indicates whether Interface is supplied in\r
+                                 native form.\r
+  @param  Interface              The interface for the protocol being added\r
+\r
+  @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestInstallProtocolInterface (\r
+  IN OUT EFI_HANDLE      *UserHandle,\r
+  IN EFI_GUID            *Protocol,\r
+  IN EFI_INTERFACE_TYPE  InterfaceType,\r
+  IN VOID                *Interface\r
+  )\r
+{\r
+  return UnitTestInstallProtocolInterfaceNotify (\r
+           UserHandle,\r
+           Protocol,\r
+           InterfaceType,\r
+           Interface,\r
+           TRUE\r
+           );\r
+}\r
+\r
+/**\r
+  Reinstall a protocol interface on a device handle.  The OldInterface for Protocol is replaced by the NewInterface.\r
+\r
+  @param  UserHandle             Handle on which the interface is to be\r
+                                 reinstalled\r
+  @param  Protocol               The numeric ID of the interface\r
+  @param  OldInterface           A pointer to the old interface\r
+  @param  NewInterface           A pointer to the new interface\r
+\r
+  @retval EFI_SUCCESS            The protocol interface was installed\r
+  @retval EFI_NOT_FOUND          The OldInterface on the handle was not found\r
+  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestReinstallProtocolInterface (\r
+  IN EFI_HANDLE  UserHandle,\r
+  IN EFI_GUID    *Protocol,\r
+  IN VOID        *OldInterface,\r
+  IN VOID        *NewInterface\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Uninstalls all instances of a protocol:interfacer from a handle.\r
+  If the last protocol interface is remove from the handle, the\r
+  handle is freed.\r
+\r
+  @param  UserHandle             The handle to remove the protocol handler from\r
+  @param  Protocol               The protocol, of protocol:interface, to remove\r
+  @param  Interface              The interface, of protocol:interface, to remove\r
+\r
+  @retval EFI_INVALID_PARAMETER  Protocol is NULL.\r
+  @retval EFI_SUCCESS            Protocol interface successfully uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestUninstallProtocolInterface (\r
+  IN EFI_HANDLE  UserHandle,\r
+  IN EFI_GUID    *Protocol,\r
+  IN VOID        *Interface\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  IHANDLE             *Handle;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+\r
+  //\r
+  // Check that Protocol is valid\r
+  //\r
+  if (Protocol == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check that UserHandle is a valid handle\r
+  //\r
+  Status = UnitTestValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
+  //\r
+  Prot = UnitTestFindProtocolInterface (UserHandle, Protocol, Interface);\r
+  if (Prot == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Attempt to disconnect all drivers that are using the protocol interface that is about to be removed\r
+  //\r
+  Status = UnitTestDisconnectControllersUsingProtocolInterface (\r
+             UserHandle,\r
+             Prot\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // One or more drivers refused to release, so return the error\r
+    //\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Remove the protocol interface from the protocol\r
+  //\r
+  Status = EFI_NOT_FOUND;\r
+  Handle = (IHANDLE *)UserHandle;\r
+  Prot   = UnitTestRemoveInterfaceFromProtocol (Handle, Protocol, Interface);\r
+\r
+  if (Prot != NULL) {\r
+    //\r
+    // Update the Key to show that the handle has been created/modified\r
+    //\r
+    gHandleDatabaseKey++;\r
+    Handle->Key = gHandleDatabaseKey;\r
+\r
+    //\r
+    // Remove the protocol interface from the handle\r
+    //\r
+    RemoveEntryList (&Prot->Link);\r
+\r
+    //\r
+    // Free the memory\r
+    //\r
+    Prot->Signature = 0;\r
+    FreePool (Prot);\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If there are no more handlers for the handle, free the handle\r
+  //\r
+  if (IsListEmpty (&Handle->Protocols)) {\r
+    Handle->Signature = 0;\r
+    RemoveEntryList (&Handle->AllHandles);\r
+    FreePool (Handle);\r
+  }\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Queries a handle to determine if it supports a specified protocol.\r
+\r
+  @param  UserHandle             The handle being queried.\r
+  @param  Protocol               The published unique identifier of the protocol.\r
+  @param  Interface              Supplies the address where a pointer to the\r
+                                 corresponding Protocol Interface is returned.\r
+\r
+  @return The requested protocol interface for the handle\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestHandleProtocol (\r
+  IN EFI_HANDLE  UserHandle,\r
+  IN EFI_GUID    *Protocol,\r
+  OUT VOID       **Interface\r
+  )\r
+{\r
+  return UnitTestOpenProtocol (\r
+           UserHandle,\r
+           Protocol,\r
+           Interface,\r
+           gImageHandle,\r
+           NULL,\r
+           EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL\r
+           );\r
+}\r
+\r
+/**\r
+  Add a new protocol notification record for the request protocol.\r
+\r
+  @param  Protocol               The requested protocol to add the notify\r
+                                 registration\r
+  @param  Event                  The event to signal\r
+  @param  Registration           Returns the registration record\r
+\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully returned the registration record\r
+                                 that has been added\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestRegisterProtocolNotify (\r
+  IN EFI_GUID   *Protocol,\r
+  IN EFI_EVENT  Event,\r
+  OUT  VOID     **Registration\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Locates the requested handle(s) and returns them in Buffer.\r
+\r
+  @param  SearchType             The type of search to perform to locate the\r
+                                 handles\r
+  @param  Protocol               The protocol to search for\r
+  @param  SearchKey              Dependant on SearchType\r
+  @param  BufferSize             On input the size of Buffer.  On output the\r
+                                 size of data returned.\r
+  @param  Buffer                 The buffer to return the results in\r
+\r
+  @retval EFI_BUFFER_TOO_SMALL   Buffer too small, required buffer size is\r
+                                 returned in BufferSize.\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_SUCCESS            Successfully found the requested handle(s) and\r
+                                 returns them in Buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestLocateHandle (\r
+  IN EFI_LOCATE_SEARCH_TYPE  SearchType,\r
+  IN EFI_GUID                *Protocol   OPTIONAL,\r
+  IN VOID                    *SearchKey  OPTIONAL,\r
+  IN OUT UINTN               *BufferSize,\r
+  OUT EFI_HANDLE             *Buffer\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  LOCATE_POSITION     Position;\r
+  PROTOCOL_NOTIFY     *ProtNotify;\r
+  UNIT_TEST_GET_NEXT  GetNext;\r
+  UINTN               ResultSize;\r
+  IHANDLE             *Handle;\r
+  IHANDLE             **ResultBuffer;\r
+  VOID                *Interface;\r
+\r
+  if (BufferSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*BufferSize > 0) && (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  GetNext = NULL;\r
+\r
+  //\r
+  // Set initial position\r
+  //\r
+  Position.Protocol  = Protocol;\r
+  Position.SearchKey = SearchKey;\r
+  Position.Position  = &gHandleList;\r
+\r
+  ResultSize   = 0;\r
+  ResultBuffer = (IHANDLE **)Buffer;\r
+  Status       = EFI_SUCCESS;\r
+\r
+  //\r
+  // Get the search function based on type\r
+  //\r
+  switch (SearchType) {\r
+    case AllHandles:\r
+      GetNext = UnitTestGetNextLocateAllHandles;\r
+      break;\r
+\r
+    case ByRegisterNotify:\r
+      //\r
+      // Must have SearchKey for locate ByRegisterNotify\r
+      //\r
+      if (SearchKey == NULL) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        break;\r
+      }\r
+\r
+      GetNext = UnitTestGetNextLocateByRegisterNotify;\r
+      break;\r
+\r
+    case ByProtocol:\r
+      GetNext = UnitTestGetNextLocateByProtocol;\r
+      if (Protocol == NULL) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        break;\r
+      }\r
+\r
+      //\r
+      // Look up the protocol entry and set the head pointer\r
+      //\r
+      Position.ProtEntry = UnitTestFindProtocolEntry (Protocol, FALSE);\r
+      if (Position.ProtEntry == NULL) {\r
+        Status = EFI_NOT_FOUND;\r
+        break;\r
+      }\r
+\r
+      Position.Position = &Position.ProtEntry->Protocols;\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_INVALID_PARAMETER;\r
+      break;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ASSERT (GetNext != NULL);\r
+  //\r
+  // Enumerate out the matching handles\r
+  //\r
+  mEfiLocateHandleRequest += 1;\r
+  for ( ; ;) {\r
+    //\r
+    // Get the next handle.  If no more handles, stop\r
+    //\r
+    Handle = GetNext (&Position, &Interface);\r
+    if (NULL == Handle) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Increase the resulting buffer size, and if this handle\r
+    // fits return it\r
+    //\r
+    ResultSize += sizeof (Handle);\r
+    if (ResultSize <= *BufferSize) {\r
+      *ResultBuffer = Handle;\r
+      ResultBuffer += 1;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the result is a zero length buffer, then there were no\r
+  // matching handles\r
+  //\r
+  if (ResultSize == 0) {\r
+    Status = EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // Return the resulting buffer size.  If it's larger than what\r
+    // was passed, then set the error code\r
+    //\r
+    if (ResultSize > *BufferSize) {\r
+      Status = EFI_BUFFER_TOO_SMALL;\r
+    }\r
+\r
+    *BufferSize = ResultSize;\r
+\r
+    if ((SearchType == ByRegisterNotify) && !EFI_ERROR (Status)) {\r
+      //\r
+      // If this is a search by register notify and a handle was\r
+      // returned, update the register notification position\r
+      //\r
+      ASSERT (SearchKey != NULL);\r
+      ProtNotify           = SearchKey;\r
+      ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Locates the handle to a device on the device path that best matches the specified protocol.\r
+\r
+  @param  Protocol               The protocol to search for.\r
+  @param  DevicePath             On input, a pointer to a pointer to the device\r
+                                 path. On output, the device path pointer is\r
+                                 modified to point to the remaining part of the\r
+                                 devicepath.\r
+  @param  Device                 A pointer to the returned device handle.\r
+\r
+  @retval EFI_SUCCESS            The resulting handle was returned.\r
+  @retval EFI_NOT_FOUND          No handles matched the search.\r
+  @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestLocateDevicePath (\r
+  IN EFI_GUID                      *Protocol,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePath,\r
+  OUT EFI_HANDLE                   *Device\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Boot Service called to add, modify, or remove a system configuration table from\r
+  the EFI System Table.\r
+\r
+  @param  Guid           Pointer to the GUID for the entry to add, update, or\r
+                         remove\r
+  @param  Table          Pointer to the configuration table for the entry to add,\r
+                         update, or remove, may be NULL.\r
+\r
+  @return EFI_SUCCESS               Guid, Table pair added, updated, or removed.\r
+  @return EFI_INVALID_PARAMETER     Input GUID not valid.\r
+  @return EFI_NOT_FOUND             Attempted to delete non-existant entry\r
+  @return EFI_OUT_OF_RESOURCES      Not enough memory available\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestInstallConfigurationTable (\r
+  IN EFI_GUID  *Guid,\r
+  IN VOID      *Table\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Locates the installed protocol handler for the handle, and\r
+  invokes it to obtain the protocol interface. Usage information\r
+  is registered in the protocol data base.\r
+\r
+  @param  UserHandle             The handle to obtain the protocol interface on\r
+  @param  Protocol               The ID of the protocol\r
+  @param  Interface              The location to return the protocol interface\r
+  @param  ImageHandle            The handle of the Image that is opening the\r
+                                 protocol interface specified by Protocol and\r
+                                 Interface.\r
+  @param  ControllerHandle       The controller handle that is requiring this\r
+                                 interface.\r
+  @param  Attributes             The open mode of the protocol interface\r
+                                 specified by Handle and Protocol.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Protocol is NULL.\r
+  @retval EFI_SUCCESS            Get the protocol interface.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestOpenProtocol (\r
+  IN  EFI_HANDLE  UserHandle,\r
+  IN  EFI_GUID    *Protocol,\r
+  OUT VOID        **Interface OPTIONAL,\r
+  IN  EFI_HANDLE  ImageHandle,\r
+  IN  EFI_HANDLE  ControllerHandle,\r
+  IN  UINT32      Attributes\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  PROTOCOL_INTERFACE  *Prot;\r
+  LIST_ENTRY          *Link;\r
+  OPEN_PROTOCOL_DATA  *OpenData;\r
+  BOOLEAN             ByDriver;\r
+  BOOLEAN             Exclusive;\r
+  BOOLEAN             Disconnect;\r
+  BOOLEAN             ExactMatch;\r
+\r
+  //\r
+  // Check for invalid Protocol\r
+  //\r
+  if (Protocol == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check for invalid Interface\r
+  //\r
+  if ((Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) && (Interface == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check for invalid UserHandle\r
+  //\r
+  Status =  UnitTestValidateHandle (UserHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check for invalid Attributes\r
+  //\r
+  switch (Attributes) {\r
+    case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:\r
+      Status =  UnitTestValidateHandle (ImageHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Status =  UnitTestValidateHandle (ControllerHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (UserHandle == ControllerHandle) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      break;\r
+    case EFI_OPEN_PROTOCOL_BY_DRIVER:\r
+    case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:\r
+      Status =  UnitTestValidateHandle (ImageHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Status =  UnitTestValidateHandle (ControllerHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      break;\r
+    case EFI_OPEN_PROTOCOL_EXCLUSIVE:\r
+      Status =  UnitTestValidateHandle (ImageHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      break;\r
+    case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:\r
+    case EFI_OPEN_PROTOCOL_GET_PROTOCOL:\r
+    case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:\r
+      break;\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Look at each protocol interface for a match\r
+  //\r
+  Prot = UnitTestGetProtocolInterface (UserHandle, Protocol);\r
+  if (Prot == NULL) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  ByDriver  = FALSE;\r
+  Exclusive = FALSE;\r
+  for ( Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {\r
+    OpenData   = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
+    ExactMatch =  (BOOLEAN)((OpenData->AgentHandle == ImageHandle) &&\r
+                            (OpenData->Attributes == Attributes)  &&\r
+                            (OpenData->ControllerHandle == ControllerHandle));\r
+    if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+      ByDriver = TRUE;\r
+      if (ExactMatch) {\r
+        Status = EFI_ALREADY_STARTED;\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) != 0) {\r
+      Exclusive = TRUE;\r
+    } else if (ExactMatch) {\r
+      OpenData->OpenCount++;\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // ByDriver  TRUE  -> A driver is managing (UserHandle, Protocol)\r
+  // ByDriver  FALSE -> There are no drivers managing (UserHandle, Protocol)\r
+  // Exclusive TRUE  -> Something has exclusive access to (UserHandle, Protocol)\r
+  // Exclusive FALSE -> Nothing has exclusive access to (UserHandle, Protocol)\r
+  //\r
+\r
+  switch (Attributes) {\r
+    case EFI_OPEN_PROTOCOL_BY_DRIVER:\r
+      if (Exclusive || ByDriver) {\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto Done;\r
+      }\r
+\r
+      break;\r
+    case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:\r
+    case EFI_OPEN_PROTOCOL_EXCLUSIVE:\r
+      if (Exclusive) {\r
+        Status = EFI_ACCESS_DENIED;\r
+        goto Done;\r
+      }\r
+\r
+      if (ByDriver) {\r
+        do {\r
+          Disconnect = FALSE;\r
+          for (Link = Prot->OpenList.ForwardLink; Link != &Prot->OpenList; Link = Link->ForwardLink) {\r
+            OpenData = CR (Link, OPEN_PROTOCOL_DATA, Link, OPEN_PROTOCOL_DATA_SIGNATURE);\r
+            if ((OpenData->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {\r
+              Disconnect = TRUE;\r
+              Status     = UnitTestDisconnectController (UserHandle, OpenData->AgentHandle, NULL);\r
+              if (EFI_ERROR (Status)) {\r
+                Status = EFI_ACCESS_DENIED;\r
+                goto Done;\r
+              } else {\r
+                break;\r
+              }\r
+            }\r
+          }\r
+        } while (Disconnect);\r
+      }\r
+\r
+      break;\r
+    case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:\r
+    case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:\r
+    case EFI_OPEN_PROTOCOL_GET_PROTOCOL:\r
+    case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:\r
+      break;\r
+  }\r
+\r
+  if (ImageHandle == NULL) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Create new entry\r
+  //\r
+  OpenData = AllocatePool (sizeof (OPEN_PROTOCOL_DATA));\r
+  if (OpenData == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  } else {\r
+    OpenData->Signature        = OPEN_PROTOCOL_DATA_SIGNATURE;\r
+    OpenData->AgentHandle      = ImageHandle;\r
+    OpenData->ControllerHandle = ControllerHandle;\r
+    OpenData->Attributes       = Attributes;\r
+    OpenData->OpenCount        = 1;\r
+    InsertTailList (&Prot->OpenList, &OpenData->Link);\r
+    Prot->OpenListCount++;\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Done:\r
+\r
+  if (Attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {\r
+    //\r
+    // Keep Interface unmodified in case of any Error\r
+    // except EFI_ALREADY_STARTED and EFI_UNSUPPORTED.\r
+    //\r
+    if (!EFI_ERROR (Status) || (Status == EFI_ALREADY_STARTED)) {\r
+      //\r
+      // According to above logic, if 'Prot' is NULL, then the 'Status' must be\r
+      // EFI_UNSUPPORTED. Here the 'Status' is not EFI_UNSUPPORTED, so 'Prot'\r
+      // must be not NULL.\r
+      //\r
+      // The ASSERT here is for addressing a false positive NULL pointer\r
+      // dereference issue raised from static analysis.\r
+      //\r
+      ASSERT (Prot != NULL);\r
+      //\r
+      // EFI_ALREADY_STARTED is not an error for bus driver.\r
+      // Return the corresponding protocol interface.\r
+      //\r
+      *Interface = Prot->Interface;\r
+    } else if (Status == EFI_UNSUPPORTED) {\r
+      //\r
+      // Return NULL Interface if Unsupported Protocol.\r
+      //\r
+      *Interface = NULL;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Closes a protocol on a handle that was opened using OpenProtocol().\r
+\r
+  @param  UserHandle             The handle for the protocol interface that was\r
+                                 previously opened with OpenProtocol(), and is\r
+                                 now being closed.\r
+  @param  Protocol               The published unique identifier of the protocol.\r
+                                 It is the caller's responsibility to pass in a\r
+                                 valid GUID.\r
+  @param  AgentHandle            The handle of the agent that is closing the\r
+                                 protocol interface.\r
+  @param  ControllerHandle       If the agent that opened a protocol is a driver\r
+                                 that follows the EFI Driver Model, then this\r
+                                 parameter is the controller handle that required\r
+                                 the protocol interface. If the agent does not\r
+                                 follow the EFI Driver Model, then this parameter\r
+                                 is optional and may be NULL.\r
+\r
+  @retval EFI_SUCCESS            The protocol instance was closed.\r
+  @retval EFI_INVALID_PARAMETER  Handle, AgentHandle or ControllerHandle is not a\r
+                                 valid EFI_HANDLE.\r
+  @retval EFI_NOT_FOUND          Can not find the specified protocol or\r
+                                 AgentHandle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestCloseProtocol (\r
+  IN  EFI_HANDLE  UserHandle,\r
+  IN  EFI_GUID    *Protocol,\r
+  IN  EFI_HANDLE  AgentHandle,\r
+  IN  EFI_HANDLE  ControllerHandle\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Return information about Opened protocols in the system\r
+\r
+  @param  UserHandle             The handle to close the protocol interface on\r
+  @param  Protocol               The ID of the protocol\r
+  @param  EntryBuffer            A pointer to a buffer of open protocol\r
+                                 information in the form of\r
+                                 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY structures.\r
+  @param  EntryCount             Number of EntryBuffer entries\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestOpenProtocolInformation (\r
+  IN  EFI_HANDLE                           UserHandle,\r
+  IN  EFI_GUID                             *Protocol,\r
+  OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  **EntryBuffer,\r
+  OUT UINTN                                *EntryCount\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated\r
+  from pool.\r
+\r
+  @param  UserHandle             The handle from which to retrieve the list of\r
+                                 protocol interface GUIDs.\r
+  @param  ProtocolBuffer         A pointer to the list of protocol interface GUID\r
+                                 pointers that are installed on Handle.\r
+  @param  ProtocolBufferCount    A pointer to the number of GUID pointers present\r
+                                 in ProtocolBuffer.\r
+\r
+  @retval EFI_SUCCESS            The list of protocol interface GUIDs installed\r
+                                 on Handle was returned in ProtocolBuffer. The\r
+                                 number of protocol interface GUIDs was returned\r
+                                 in ProtocolBufferCount.\r
+  @retval EFI_INVALID_PARAMETER  Handle is NULL.\r
+  @retval EFI_INVALID_PARAMETER  Handle is not a valid EFI_HANDLE.\r
+  @retval EFI_INVALID_PARAMETER  ProtocolBuffer is NULL.\r
+  @retval EFI_INVALID_PARAMETER  ProtocolBufferCount is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the\r
+                                 results.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestProtocolsPerHandle (\r
+  IN EFI_HANDLE  UserHandle,\r
+  OUT EFI_GUID   ***ProtocolBuffer,\r
+  OUT UINTN      *ProtocolBufferCount\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Function returns an array of handles that support the requested protocol\r
+  in a buffer allocated from pool. This is a version of UnitTestLocateHandle()\r
+  that allocates a buffer for the caller.\r
+\r
+  @param  SearchType             Specifies which handle(s) are to be returned.\r
+  @param  Protocol               Provides the protocol to search by.    This\r
+                                 parameter is only valid for SearchType\r
+                                 ByProtocol.\r
+  @param  SearchKey              Supplies the search key depending on the\r
+                                 SearchType.\r
+  @param  NumberHandles          The number of handles returned in Buffer.\r
+  @param  Buffer                 A pointer to the buffer to return the requested\r
+                                 array of  handles that support Protocol.\r
+\r
+  @retval EFI_SUCCESS            The result array of handles was returned.\r
+  @retval EFI_NOT_FOUND          No handles match the search.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the\r
+                                 matching results.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestLocateHandleBuffer (\r
+  IN EFI_LOCATE_SEARCH_TYPE  SearchType,\r
+  IN EFI_GUID                *Protocol OPTIONAL,\r
+  IN VOID                    *SearchKey OPTIONAL,\r
+  IN OUT UINTN               *NumberHandles,\r
+  OUT EFI_HANDLE             **Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BufferSize;\r
+\r
+  if (NumberHandles == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize     = 0;\r
+  *NumberHandles = 0;\r
+  *Buffer        = NULL;\r
+  Status         = UnitTestLocateHandle (\r
+                     SearchType,\r
+                     Protocol,\r
+                     SearchKey,\r
+                     &BufferSize,\r
+                     *Buffer\r
+                     );\r
+  //\r
+  // LocateHandleBuffer() returns incorrect status code if SearchType is\r
+  // invalid.\r
+  //\r
+  // Add code to correctly handle expected errors from UnitTestLocateHandle().\r
+  //\r
+  if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+    if (Status != EFI_INVALID_PARAMETER) {\r
+      Status = EFI_NOT_FOUND;\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  *Buffer = AllocatePool (BufferSize);\r
+  if (*Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = UnitTestLocateHandle (\r
+             SearchType,\r
+             Protocol,\r
+             SearchKey,\r
+             &BufferSize,\r
+             *Buffer\r
+             );\r
+\r
+  *NumberHandles = BufferSize / sizeof (EFI_HANDLE);\r
+  if (EFI_ERROR (Status)) {\r
+    *NumberHandles = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Return the first Protocol Interface that matches the Protocol GUID. If\r
+  Registration is passed in, return a Protocol Instance that was just add\r
+  to the system. If Registration is NULL return the first Protocol Interface\r
+  you find.\r
+\r
+  @param  Protocol               The protocol to search for\r
+  @param  Registration           Optional Registration Key returned from\r
+                                 RegisterProtocolNotify()\r
+  @param  Interface              Return the Protocol interface (instance).\r
+\r
+  @retval EFI_SUCCESS            If a valid Interface is returned\r
+  @retval EFI_INVALID_PARAMETER  Invalid parameter\r
+  @retval EFI_NOT_FOUND          Protocol interface not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestLocateProtocol (\r
+  IN  EFI_GUID  *Protocol,\r
+  IN  VOID      *Registration OPTIONAL,\r
+  OUT VOID      **Interface\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Installs a list of protocol interface into the boot services environment.\r
+  This function calls InstallProtocolInterface() in a loop. If any error\r
+  occurs all the protocols added by this function are removed. This is\r
+  basically a lib function to save space.\r
+\r
+  @param  Handle                 The handle to install the protocol handlers on,\r
+                                 or NULL if a new handle is to be allocated\r
+  @param  ...                    EFI_GUID followed by protocol instance. A NULL\r
+                                 terminates the  list. The pairs are the\r
+                                 arguments to InstallProtocolInterface(). All the\r
+                                 protocols are added to Handle.\r
+\r
+  @retval EFI_SUCCESS            All the protocol interface was installed.\r
+  @retval EFI_OUT_OF_RESOURCES   There was not enough memory in pool to install all the protocols.\r
+  @retval EFI_ALREADY_STARTED    A Device Path Protocol instance was passed in that is already present in\r
+                                 the handle database.\r
+  @retval EFI_INVALID_PARAMETER  Handle is NULL.\r
+  @retval EFI_INVALID_PARAMETER  Protocol is already installed on the handle specified by Handle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestInstallMultipleProtocolInterfaces (\r
+  IN OUT EFI_HANDLE  *Handle,\r
+  ...\r
+  )\r
+{\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Uninstalls a list of protocol interface in the boot services environment.\r
+  This function calls UninstallProtocolInterface() in a loop. This is\r
+  basically a lib function to save space.\r
+\r
+  @param  Handle                 The handle to uninstall the protocol\r
+  @param  ...                    EFI_GUID followed by protocol instance. A NULL\r
+                                 terminates the  list. The pairs are the\r
+                                 arguments to UninstallProtocolInterface(). All\r
+                                 the protocols are added to Handle.\r
+\r
+  @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UnitTestUninstallMultipleProtocolInterfaces (\r
+  IN EFI_HANDLE  Handle,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  VA_LIST     Args;\r
+  EFI_GUID    *Protocol;\r
+  VOID        *Interface;\r
+  UINTN       Index;\r
+\r
+  VA_START (Args, Handle);\r
+  for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {\r
+    //\r
+    // If protocol is NULL, then it's the end of the list\r
+    //\r
+    Protocol = VA_ARG (Args, EFI_GUID *);\r
+    if (Protocol == NULL) {\r
+      break;\r
+    }\r
+\r
+    Interface = VA_ARG (Args, VOID *);\r
+\r
+    //\r
+    // Uninstall it\r
+    //\r
+    Status = UnitTestUninstallProtocolInterface (Handle, Protocol, Interface);\r
+  }\r
+\r
+  VA_END (Args);\r
+\r
+  //\r
+  // If there was an error, add all the interfaces that were\r
+  // uninstalled without any errors\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Reset the va_arg back to the first argument.\r
+    //\r
+    VA_START (Args, Handle);\r
+    for ( ; Index > 1; Index--) {\r
+      Protocol  = VA_ARG (Args, EFI_GUID *);\r
+      Interface = VA_ARG (Args, VOID *);\r
+      UnitTestInstallProtocolInterface (&Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);\r
+    }\r
+\r
+    VA_END (Args);\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r