Home | History | Annotate | Download | only in Hand
      1 /** @file
      2   Support functions for UEFI protocol notification infrastructure.
      3 
      4 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "DxeMain.h"
     17 #include "Handle.h"
     18 #include "Event.h"
     19 
     20 /**
     21   Signal event for every protocol in protocol entry.
     22 
     23   @param  ProtEntry              Protocol entry
     24 
     25 **/
     26 VOID
     27 CoreNotifyProtocolEntry (
     28   IN PROTOCOL_ENTRY   *ProtEntry
     29   )
     30 {
     31   PROTOCOL_NOTIFY     *ProtNotify;
     32   LIST_ENTRY          *Link;
     33 
     34   ASSERT_LOCKED (&gProtocolDatabaseLock);
     35 
     36   for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
     37     ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
     38     CoreSignalEvent (ProtNotify->Event);
     39   }
     40 }
     41 
     42 
     43 
     44 /**
     45   Removes Protocol from the protocol list (but not the handle list).
     46 
     47   @param  Handle                 The handle to remove protocol on.
     48   @param  Protocol               GUID of the protocol to be moved
     49   @param  Interface              The interface of the protocol
     50 
     51   @return Protocol Entry
     52 
     53 **/
     54 PROTOCOL_INTERFACE *
     55 CoreRemoveInterfaceFromProtocol (
     56   IN IHANDLE        *Handle,
     57   IN EFI_GUID       *Protocol,
     58   IN VOID           *Interface
     59   )
     60 {
     61   PROTOCOL_INTERFACE  *Prot;
     62   PROTOCOL_NOTIFY     *ProtNotify;
     63   PROTOCOL_ENTRY      *ProtEntry;
     64   LIST_ENTRY          *Link;
     65 
     66   ASSERT_LOCKED (&gProtocolDatabaseLock);
     67 
     68   Prot = CoreFindProtocolInterface (Handle, Protocol, Interface);
     69   if (Prot != NULL) {
     70 
     71     ProtEntry = Prot->Protocol;
     72 
     73     //
     74     // If there's a protocol notify location pointing to this entry, back it up one
     75     //
     76     for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
     77       ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
     78 
     79       if (ProtNotify->Position == &Prot->ByProtocol) {
     80         ProtNotify->Position = Prot->ByProtocol.BackLink;
     81       }
     82     }
     83 
     84     //
     85     // Remove the protocol interface entry
     86     //
     87     RemoveEntryList (&Prot->ByProtocol);
     88   }
     89 
     90   return Prot;
     91 }
     92 
     93 
     94 /**
     95   Add a new protocol notification record for the request protocol.
     96 
     97   @param  Protocol               The requested protocol to add the notify
     98                                  registration
     99   @param  Event                  The event to signal
    100   @param  Registration           Returns the registration record
    101 
    102   @retval EFI_INVALID_PARAMETER  Invalid parameter
    103   @retval EFI_SUCCESS            Successfully returned the registration record
    104                                  that has been added
    105 
    106 **/
    107 EFI_STATUS
    108 EFIAPI
    109 CoreRegisterProtocolNotify (
    110   IN EFI_GUID       *Protocol,
    111   IN EFI_EVENT      Event,
    112   OUT  VOID         **Registration
    113   )
    114 {
    115   PROTOCOL_ENTRY    *ProtEntry;
    116   PROTOCOL_NOTIFY   *ProtNotify;
    117   EFI_STATUS        Status;
    118 
    119   if ((Protocol == NULL) || (Event == NULL) || (Registration == NULL))  {
    120     return EFI_INVALID_PARAMETER;
    121   }
    122 
    123   CoreAcquireProtocolLock ();
    124 
    125   ProtNotify = NULL;
    126 
    127   //
    128   // Get the protocol entry to add the notification too
    129   //
    130 
    131   ProtEntry = CoreFindProtocolEntry (Protocol, TRUE);
    132   if (ProtEntry != NULL) {
    133 
    134     //
    135     // Allocate a new notification record
    136     //
    137     ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
    138     if (ProtNotify != NULL) {
    139       ((IEVENT *)Event)->ExFlag |= EVT_EXFLAG_EVENT_PROTOCOL_NOTIFICATION;
    140       ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
    141       ProtNotify->Protocol = ProtEntry;
    142       ProtNotify->Event = Event;
    143       //
    144       // start at the begining
    145       //
    146       ProtNotify->Position = &ProtEntry->Protocols;
    147 
    148       InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
    149     }
    150   }
    151 
    152   CoreReleaseProtocolLock ();
    153 
    154   //
    155   // Done.  If we have a protocol notify entry, then return it.
    156   // Otherwise, we must have run out of resources trying to add one
    157   //
    158 
    159   Status = EFI_OUT_OF_RESOURCES;
    160   if (ProtNotify != NULL) {
    161     *Registration = ProtNotify;
    162     Status = EFI_SUCCESS;
    163   }
    164 
    165   return Status;
    166 }
    167 
    168 
    169 /**
    170   Reinstall a protocol interface on a device handle.  The OldInterface for Protocol is replaced by the NewInterface.
    171 
    172   @param  UserHandle             Handle on which the interface is to be
    173                                  reinstalled
    174   @param  Protocol               The numeric ID of the interface
    175   @param  OldInterface           A pointer to the old interface
    176   @param  NewInterface           A pointer to the new interface
    177 
    178   @retval EFI_SUCCESS            The protocol interface was installed
    179   @retval EFI_NOT_FOUND          The OldInterface on the handle was not found
    180   @retval EFI_INVALID_PARAMETER  One of the parameters has an invalid value
    181 
    182 **/
    183 EFI_STATUS
    184 EFIAPI
    185 CoreReinstallProtocolInterface (
    186   IN EFI_HANDLE     UserHandle,
    187   IN EFI_GUID       *Protocol,
    188   IN VOID           *OldInterface,
    189   IN VOID           *NewInterface
    190   )
    191 {
    192   EFI_STATUS                Status;
    193   IHANDLE                   *Handle;
    194   PROTOCOL_INTERFACE        *Prot;
    195   PROTOCOL_ENTRY            *ProtEntry;
    196 
    197   Status = CoreValidateHandle (UserHandle);
    198   if (EFI_ERROR (Status)) {
    199     return Status;
    200   }
    201 
    202   if (Protocol == NULL) {
    203     return EFI_INVALID_PARAMETER;
    204   }
    205 
    206   Handle = (IHANDLE *) UserHandle;
    207 
    208   //
    209   // Lock the protocol database
    210   //
    211   CoreAcquireProtocolLock ();
    212 
    213   //
    214   // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
    215   //
    216   Prot = CoreFindProtocolInterface (UserHandle, Protocol, OldInterface);
    217   if (Prot == NULL) {
    218     Status = EFI_NOT_FOUND;
    219     goto Done;
    220   }
    221 
    222   //
    223   // Attempt to disconnect all drivers that are using the protocol interface that is about to be reinstalled
    224   //
    225   Status = CoreDisconnectControllersUsingProtocolInterface (
    226              UserHandle,
    227              Prot
    228              );
    229   if (EFI_ERROR (Status)) {
    230     //
    231     // One or more drivers refused to release, so return the error
    232     //
    233     goto Done;
    234   }
    235 
    236   //
    237   // Remove the protocol interface from the protocol
    238   //
    239   Prot = CoreRemoveInterfaceFromProtocol (Handle, Protocol, OldInterface);
    240 
    241   if (Prot == NULL) {
    242     Status = EFI_NOT_FOUND;
    243     goto Done;
    244   }
    245 
    246   ProtEntry = Prot->Protocol;
    247 
    248   //
    249   // Update the interface on the protocol
    250   //
    251   Prot->Interface = NewInterface;
    252 
    253   //
    254   // Add this protocol interface to the tail of the
    255   // protocol entry
    256   //
    257   InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
    258 
    259   //
    260   // Update the Key to show that the handle has been created/modified
    261   //
    262   gHandleDatabaseKey++;
    263   Handle->Key = gHandleDatabaseKey;
    264 
    265   //
    266   // Release the lock and connect all drivers to UserHandle
    267   //
    268   CoreReleaseProtocolLock ();
    269   //
    270   // Return code is ignored on purpose.
    271   //
    272   CoreConnectController (
    273     UserHandle,
    274     NULL,
    275     NULL,
    276     TRUE
    277     );
    278   CoreAcquireProtocolLock ();
    279 
    280   //
    281   // Notify the notification list for this protocol
    282   //
    283   CoreNotifyProtocolEntry (ProtEntry);
    284 
    285   Status = EFI_SUCCESS;
    286 
    287 Done:
    288   CoreReleaseProtocolLock ();
    289 
    290   return Status;
    291 }
    292