Home | History | Annotate | Download | only in PiSmmCore
      1 /** @file
      2   Support functions for UEFI protocol notification infrastructure.
      3 
      4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials are licensed and made available
      6   under the terms and conditions of the BSD License which accompanies this
      7   distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PiSmmCore.h"
     16 
     17 /**
     18   Signal event for every protocol in protocol entry.
     19 
     20   @param  Prot                   Protocol interface
     21 
     22 **/
     23 VOID
     24 SmmNotifyProtocol (
     25   IN PROTOCOL_INTERFACE  *Prot
     26   )
     27 {
     28   PROTOCOL_ENTRY   *ProtEntry;
     29   PROTOCOL_NOTIFY  *ProtNotify;
     30   LIST_ENTRY       *Link;
     31 
     32   ProtEntry = Prot->Protocol;
     33   for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
     34     ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
     35     ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);
     36   }
     37 }
     38 
     39 /**
     40   Removes Protocol from the protocol list (but not the handle list).
     41 
     42   @param  Handle                 The handle to remove protocol on.
     43   @param  Protocol               GUID of the protocol to be moved
     44   @param  Interface              The interface of the protocol
     45 
     46   @return Protocol Entry
     47 
     48 **/
     49 PROTOCOL_INTERFACE *
     50 SmmRemoveInterfaceFromProtocol (
     51   IN IHANDLE   *Handle,
     52   IN EFI_GUID  *Protocol,
     53   IN VOID      *Interface
     54   )
     55 {
     56   PROTOCOL_INTERFACE  *Prot;
     57   PROTOCOL_NOTIFY     *ProtNotify;
     58   PROTOCOL_ENTRY      *ProtEntry;
     59   LIST_ENTRY          *Link;
     60 
     61   Prot = SmmFindProtocolInterface (Handle, Protocol, Interface);
     62   if (Prot != NULL) {
     63 
     64     ProtEntry = Prot->Protocol;
     65 
     66     //
     67     // If there's a protocol notify location pointing to this entry, back it up one
     68     //
     69     for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {
     70       ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
     71 
     72       if (ProtNotify->Position == &Prot->ByProtocol) {
     73         ProtNotify->Position = Prot->ByProtocol.BackLink;
     74       }
     75     }
     76 
     77     //
     78     // Remove the protocol interface entry
     79     //
     80     RemoveEntryList (&Prot->ByProtocol);
     81   }
     82 
     83   return Prot;
     84 }
     85 
     86 /**
     87   Add a new protocol notification record for the request protocol.
     88 
     89   @param  Protocol               The requested protocol to add the notify
     90                                  registration
     91   @param  Function               Points to the notification function
     92   @param  Registration           Returns the registration record
     93 
     94   @retval EFI_SUCCESS            Successfully returned the registration record
     95                                  that has been added or unhooked
     96   @retval EFI_INVALID_PARAMETER  Protocol is NULL or Registration is NULL
     97   @retval EFI_OUT_OF_RESOURCES   Not enough memory resource to finish the request
     98   @retval EFI_NOT_FOUND          If the registration is not found when Function == NULL
     99 
    100 **/
    101 EFI_STATUS
    102 EFIAPI
    103 SmmRegisterProtocolNotify (
    104   IN  CONST EFI_GUID     *Protocol,
    105   IN  EFI_SMM_NOTIFY_FN  Function,
    106   OUT VOID               **Registration
    107   )
    108 {
    109   PROTOCOL_ENTRY   *ProtEntry;
    110   PROTOCOL_NOTIFY  *ProtNotify;
    111   LIST_ENTRY       *Link;
    112   EFI_STATUS       Status;
    113 
    114   if (Protocol == NULL || Registration == NULL) {
    115     return EFI_INVALID_PARAMETER;
    116   }
    117 
    118   if (Function == NULL) {
    119   	//
    120     // Get the protocol entry per Protocol
    121     //
    122     ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, FALSE);
    123     if (ProtEntry != NULL) {
    124       ProtNotify = (PROTOCOL_NOTIFY * )*Registration;
    125       for (Link = ProtEntry->Notify.ForwardLink;
    126            Link != &ProtEntry->Notify;
    127            Link = Link->ForwardLink) {
    128         //
    129         // Compare the notification record
    130         //
    131         if (ProtNotify == (CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE))){
    132           //
    133           // If Registration is an existing registration, then unhook it
    134           //
    135           ProtNotify->Signature = 0;
    136           RemoveEntryList (&ProtNotify->Link);
    137           FreePool (ProtNotify);
    138           return EFI_SUCCESS;
    139         }
    140       }
    141     }
    142     //
    143     // If the registration is not found
    144     //
    145     return EFI_NOT_FOUND;
    146   }
    147 
    148   ProtNotify = NULL;
    149 
    150   //
    151   // Get the protocol entry to add the notification too
    152   //
    153   ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);
    154   if (ProtEntry != NULL) {
    155     //
    156     // Find whether notification already exist
    157     //
    158     for (Link = ProtEntry->Notify.ForwardLink;
    159          Link != &ProtEntry->Notify;
    160          Link = Link->ForwardLink) {
    161 
    162       ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);
    163       if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&
    164           (ProtNotify->Function == Function)) {
    165 
    166         //
    167         // Notification already exist
    168         //
    169         *Registration = ProtNotify;
    170 
    171         return EFI_SUCCESS;
    172       }
    173     }
    174 
    175     //
    176     // Allocate a new notification record
    177     //
    178     ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));
    179     if (ProtNotify != NULL) {
    180       ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;
    181       ProtNotify->Protocol = ProtEntry;
    182       ProtNotify->Function = Function;
    183       //
    184       // Start at the ending
    185       //
    186       ProtNotify->Position = ProtEntry->Protocols.BackLink;
    187 
    188       InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);
    189     }
    190   }
    191 
    192   //
    193   // Done.  If we have a protocol notify entry, then return it.
    194   // Otherwise, we must have run out of resources trying to add one
    195   //
    196   Status = EFI_OUT_OF_RESOURCES;
    197   if (ProtNotify != NULL) {
    198     *Registration = ProtNotify;
    199     Status = EFI_SUCCESS;
    200   }
    201   return Status;
    202 }
    203