Home | History | Annotate | Download | only in PiSmmCore
      1 /** @file
      2   SMM handle & protocol handling.
      3 
      4   Copyright (c) 2009 - 2010, 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 // mProtocolDatabase     - A list of all protocols in the system.  (simple list for now)
     19 // gHandleList           - A list of all the handles in the system
     20 //
     21 LIST_ENTRY  mProtocolDatabase  = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);
     22 LIST_ENTRY  gHandleList        = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);
     23 
     24 /**
     25   Check whether a handle is a valid EFI_HANDLE
     26 
     27   @param  UserHandle             The handle to check
     28 
     29   @retval EFI_INVALID_PARAMETER  The handle is NULL or not a valid EFI_HANDLE.
     30   @retval EFI_SUCCESS            The handle is valid EFI_HANDLE.
     31 
     32 **/
     33 EFI_STATUS
     34 SmmValidateHandle (
     35   IN EFI_HANDLE  UserHandle
     36   )
     37 {
     38   IHANDLE  *Handle;
     39 
     40   Handle = (IHANDLE *)UserHandle;
     41   if (Handle == NULL) {
     42     return EFI_INVALID_PARAMETER;
     43   }
     44   if (Handle->Signature != EFI_HANDLE_SIGNATURE) {
     45     return EFI_INVALID_PARAMETER;
     46   }
     47   return EFI_SUCCESS;
     48 }
     49 
     50 /**
     51   Finds the protocol entry for the requested protocol.
     52 
     53   @param  Protocol               The ID of the protocol
     54   @param  Create                 Create a new entry if not found
     55 
     56   @return Protocol entry
     57 
     58 **/
     59 PROTOCOL_ENTRY  *
     60 SmmFindProtocolEntry (
     61   IN EFI_GUID   *Protocol,
     62   IN BOOLEAN    Create
     63   )
     64 {
     65   LIST_ENTRY          *Link;
     66   PROTOCOL_ENTRY      *Item;
     67   PROTOCOL_ENTRY      *ProtEntry;
     68 
     69   //
     70   // Search the database for the matching GUID
     71   //
     72 
     73   ProtEntry = NULL;
     74   for (Link = mProtocolDatabase.ForwardLink;
     75        Link != &mProtocolDatabase;
     76        Link = Link->ForwardLink) {
     77 
     78     Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);
     79     if (CompareGuid (&Item->ProtocolID, Protocol)) {
     80       //
     81       // This is the protocol entry
     82       //
     83       ProtEntry = Item;
     84       break;
     85     }
     86   }
     87 
     88   //
     89   // If the protocol entry was not found and Create is TRUE, then
     90   // allocate a new entry
     91   //
     92   if ((ProtEntry == NULL) && Create) {
     93     ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));
     94     if (ProtEntry != NULL) {
     95       //
     96       // Initialize new protocol entry structure
     97       //
     98       ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;
     99       CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);
    100       InitializeListHead (&ProtEntry->Protocols);
    101       InitializeListHead (&ProtEntry->Notify);
    102 
    103       //
    104       // Add it to protocol database
    105       //
    106       InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);
    107     }
    108   }
    109   return ProtEntry;
    110 }
    111 
    112 /**
    113   Finds the protocol instance for the requested handle and protocol.
    114   Note: This function doesn't do parameters checking, it's caller's responsibility
    115   to pass in valid parameters.
    116 
    117   @param  Handle                 The handle to search the protocol on
    118   @param  Protocol               GUID of the protocol
    119   @param  Interface              The interface for the protocol being searched
    120 
    121   @return Protocol instance (NULL: Not found)
    122 
    123 **/
    124 PROTOCOL_INTERFACE *
    125 SmmFindProtocolInterface (
    126   IN IHANDLE   *Handle,
    127   IN EFI_GUID  *Protocol,
    128   IN VOID      *Interface
    129   )
    130 {
    131   PROTOCOL_INTERFACE  *Prot;
    132   PROTOCOL_ENTRY      *ProtEntry;
    133   LIST_ENTRY          *Link;
    134 
    135   Prot = NULL;
    136 
    137   //
    138   // Lookup the protocol entry for this protocol ID
    139   //
    140   ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);
    141   if (ProtEntry != NULL) {
    142     //
    143     // Look at each protocol interface for any matches
    144     //
    145     for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {
    146       //
    147       // If this protocol interface matches, remove it
    148       //
    149       Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
    150       if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {
    151         break;
    152       }
    153       Prot = NULL;
    154     }
    155   }
    156   return Prot;
    157 }
    158 
    159 /**
    160   Wrapper function to SmmInstallProtocolInterfaceNotify.  This is the public API which
    161   Calls the private one which contains a BOOLEAN parameter for notifications
    162 
    163   @param  UserHandle             The handle to install the protocol handler on,
    164                                  or NULL if a new handle is to be allocated
    165   @param  Protocol               The protocol to add to the handle
    166   @param  InterfaceType          Indicates whether Interface is supplied in
    167                                  native form.
    168   @param  Interface              The interface for the protocol being added
    169 
    170   @return Status code
    171 
    172 **/
    173 EFI_STATUS
    174 EFIAPI
    175 SmmInstallProtocolInterface (
    176   IN OUT EFI_HANDLE      *UserHandle,
    177   IN EFI_GUID            *Protocol,
    178   IN EFI_INTERFACE_TYPE  InterfaceType,
    179   IN VOID                *Interface
    180   )
    181 {
    182   return SmmInstallProtocolInterfaceNotify (
    183            UserHandle,
    184            Protocol,
    185            InterfaceType,
    186            Interface,
    187            TRUE
    188            );
    189 }
    190 
    191 /**
    192   Installs a protocol interface into the boot services environment.
    193 
    194   @param  UserHandle             The handle to install the protocol handler on,
    195                                  or NULL if a new handle is to be allocated
    196   @param  Protocol               The protocol to add to the handle
    197   @param  InterfaceType          Indicates whether Interface is supplied in
    198                                  native form.
    199   @param  Interface              The interface for the protocol being added
    200   @param  Notify                 indicates whether notify the notification list
    201                                  for this protocol
    202 
    203   @retval EFI_INVALID_PARAMETER  Invalid parameter
    204   @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate
    205   @retval EFI_SUCCESS            Protocol interface successfully installed
    206 
    207 **/
    208 EFI_STATUS
    209 SmmInstallProtocolInterfaceNotify (
    210   IN OUT EFI_HANDLE          *UserHandle,
    211   IN     EFI_GUID            *Protocol,
    212   IN     EFI_INTERFACE_TYPE  InterfaceType,
    213   IN     VOID                *Interface,
    214   IN     BOOLEAN             Notify
    215   )
    216 {
    217   PROTOCOL_INTERFACE  *Prot;
    218   PROTOCOL_ENTRY      *ProtEntry;
    219   IHANDLE             *Handle;
    220   EFI_STATUS          Status;
    221   VOID                *ExistingInterface;
    222 
    223   //
    224   // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.
    225   // Also added check for invalid UserHandle and Protocol pointers.
    226   //
    227   if (UserHandle == NULL || Protocol == NULL) {
    228     return EFI_INVALID_PARAMETER;
    229   }
    230 
    231   if (InterfaceType != EFI_NATIVE_INTERFACE) {
    232     return EFI_INVALID_PARAMETER;
    233   }
    234 
    235   //
    236   // Print debug message
    237   //
    238   DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));
    239 
    240   Status = EFI_OUT_OF_RESOURCES;
    241   Prot = NULL;
    242   Handle = NULL;
    243 
    244   if (*UserHandle != NULL) {
    245     Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);
    246     if (!EFI_ERROR (Status)) {
    247       return EFI_INVALID_PARAMETER;
    248     }
    249   }
    250 
    251   //
    252   // Lookup the Protocol Entry for the requested protocol
    253   //
    254   ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);
    255   if (ProtEntry == NULL) {
    256     goto Done;
    257   }
    258 
    259   //
    260   // Allocate a new protocol interface structure
    261   //
    262   Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));
    263   if (Prot == NULL) {
    264     Status = EFI_OUT_OF_RESOURCES;
    265     goto Done;
    266   }
    267 
    268   //
    269   // If caller didn't supply a handle, allocate a new one
    270   //
    271   Handle = (IHANDLE *)*UserHandle;
    272   if (Handle == NULL) {
    273     Handle = AllocateZeroPool (sizeof(IHANDLE));
    274     if (Handle == NULL) {
    275       Status = EFI_OUT_OF_RESOURCES;
    276       goto Done;
    277     }
    278 
    279     //
    280     // Initialize new handler structure
    281     //
    282     Handle->Signature = EFI_HANDLE_SIGNATURE;
    283     InitializeListHead (&Handle->Protocols);
    284 
    285     //
    286     // Add this handle to the list global list of all handles
    287     // in the system
    288     //
    289     InsertTailList (&gHandleList, &Handle->AllHandles);
    290   }
    291 
    292   Status = SmmValidateHandle (Handle);
    293   if (EFI_ERROR (Status)) {
    294     goto Done;
    295   }
    296 
    297   //
    298   // Each interface that is added must be unique
    299   //
    300   ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);
    301 
    302   //
    303   // Initialize the protocol interface structure
    304   //
    305   Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;
    306   Prot->Handle = Handle;
    307   Prot->Protocol = ProtEntry;
    308   Prot->Interface = Interface;
    309 
    310   //
    311   // Add this protocol interface to the head of the supported
    312   // protocol list for this handle
    313   //
    314   InsertHeadList (&Handle->Protocols, &Prot->Link);
    315 
    316   //
    317   // Add this protocol interface to the tail of the
    318   // protocol entry
    319   //
    320   InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);
    321 
    322   //
    323   // Notify the notification list for this protocol
    324   //
    325   if (Notify) {
    326     SmmNotifyProtocol (Prot);
    327   }
    328   Status = EFI_SUCCESS;
    329 
    330 Done:
    331   if (!EFI_ERROR (Status)) {
    332     //
    333     // Return the new handle back to the caller
    334     //
    335     *UserHandle = Handle;
    336   } else {
    337     //
    338     // There was an error, clean up
    339     //
    340     if (Prot != NULL) {
    341       FreePool (Prot);
    342     }
    343   }
    344   return Status;
    345 }
    346 
    347 /**
    348   Uninstalls all instances of a protocol:interfacer from a handle.
    349   If the last protocol interface is remove from the handle, the
    350   handle is freed.
    351 
    352   @param  UserHandle             The handle to remove the protocol handler from
    353   @param  Protocol               The protocol, of protocol:interface, to remove
    354   @param  Interface              The interface, of protocol:interface, to remove
    355 
    356   @retval EFI_INVALID_PARAMETER  Protocol is NULL.
    357   @retval EFI_SUCCESS            Protocol interface successfully uninstalled.
    358 
    359 **/
    360 EFI_STATUS
    361 EFIAPI
    362 SmmUninstallProtocolInterface (
    363   IN EFI_HANDLE  UserHandle,
    364   IN EFI_GUID    *Protocol,
    365   IN VOID        *Interface
    366   )
    367 {
    368   EFI_STATUS          Status;
    369   IHANDLE             *Handle;
    370   PROTOCOL_INTERFACE  *Prot;
    371 
    372   //
    373   // Check that Protocol is valid
    374   //
    375   if (Protocol == NULL) {
    376     return EFI_INVALID_PARAMETER;
    377   }
    378 
    379   //
    380   // Check that UserHandle is a valid handle
    381   //
    382   Status = SmmValidateHandle (UserHandle);
    383   if (EFI_ERROR (Status)) {
    384     return Status;
    385   }
    386 
    387   //
    388   // Check that Protocol exists on UserHandle, and Interface matches the interface in the database
    389   //
    390   Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);
    391   if (Prot == NULL) {
    392     return EFI_NOT_FOUND;
    393   }
    394 
    395   //
    396   // Remove the protocol interface from the protocol
    397   //
    398   Status = EFI_NOT_FOUND;
    399   Handle = (IHANDLE *)UserHandle;
    400   Prot   = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);
    401 
    402   if (Prot != NULL) {
    403     //
    404     // Remove the protocol interface from the handle
    405     //
    406     RemoveEntryList (&Prot->Link);
    407 
    408     //
    409     // Free the memory
    410     //
    411     Prot->Signature = 0;
    412     FreePool (Prot);
    413     Status = EFI_SUCCESS;
    414   }
    415 
    416   //
    417   // If there are no more handlers for the handle, free the handle
    418   //
    419   if (IsListEmpty (&Handle->Protocols)) {
    420     Handle->Signature = 0;
    421     RemoveEntryList (&Handle->AllHandles);
    422     FreePool (Handle);
    423   }
    424   return Status;
    425 }
    426 
    427 /**
    428   Locate a certain GUID protocol interface in a Handle's protocols.
    429 
    430   @param  UserHandle             The handle to obtain the protocol interface on
    431   @param  Protocol               The GUID of the protocol
    432 
    433   @return The requested protocol interface for the handle
    434 
    435 **/
    436 PROTOCOL_INTERFACE  *
    437 SmmGetProtocolInterface (
    438   IN EFI_HANDLE  UserHandle,
    439   IN EFI_GUID    *Protocol
    440   )
    441 {
    442   EFI_STATUS          Status;
    443   PROTOCOL_ENTRY      *ProtEntry;
    444   PROTOCOL_INTERFACE  *Prot;
    445   IHANDLE             *Handle;
    446   LIST_ENTRY          *Link;
    447 
    448   Status = SmmValidateHandle (UserHandle);
    449   if (EFI_ERROR (Status)) {
    450     return NULL;
    451   }
    452 
    453   Handle = (IHANDLE *)UserHandle;
    454 
    455   //
    456   // Look at each protocol interface for a match
    457   //
    458   for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
    459     Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
    460     ProtEntry = Prot->Protocol;
    461     if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
    462       return Prot;
    463     }
    464   }
    465   return NULL;
    466 }
    467 
    468 /**
    469   Queries a handle to determine if it supports a specified protocol.
    470 
    471   @param  UserHandle             The handle being queried.
    472   @param  Protocol               The published unique identifier of the protocol.
    473   @param  Interface              Supplies the address where a pointer to the
    474                                  corresponding Protocol Interface is returned.
    475 
    476   @retval EFI_SUCCESS            The interface information for the specified protocol was returned.
    477   @retval EFI_UNSUPPORTED        The device does not support the specified protocol.
    478   @retval EFI_INVALID_PARAMETER  Handle is not a valid EFI_HANDLE..
    479   @retval EFI_INVALID_PARAMETER  Protocol is NULL.
    480   @retval EFI_INVALID_PARAMETER  Interface is NULL.
    481 
    482 **/
    483 EFI_STATUS
    484 EFIAPI
    485 SmmHandleProtocol (
    486   IN  EFI_HANDLE  UserHandle,
    487   IN  EFI_GUID    *Protocol,
    488   OUT VOID        **Interface
    489   )
    490 {
    491   EFI_STATUS          Status;
    492   PROTOCOL_INTERFACE  *Prot;
    493 
    494   //
    495   // Check for invalid Protocol
    496   //
    497   if (Protocol == NULL) {
    498     return EFI_INVALID_PARAMETER;
    499   }
    500 
    501   //
    502   // Check for invalid Interface
    503   //
    504   if (Interface == NULL) {
    505     return EFI_INVALID_PARAMETER;
    506   } else {
    507     *Interface = NULL;
    508   }
    509 
    510   //
    511   // Check for invalid UserHandle
    512   //
    513   Status = SmmValidateHandle (UserHandle);
    514   if (EFI_ERROR (Status)) {
    515     return Status;
    516   }
    517 
    518   //
    519   // Look at each protocol interface for a match
    520   //
    521   Prot = SmmGetProtocolInterface (UserHandle, Protocol);
    522   if (Prot == NULL) {
    523     return EFI_UNSUPPORTED;
    524   }
    525 
    526   //
    527   // This is the protocol interface entry for this protocol
    528   //
    529   *Interface = Prot->Interface;
    530 
    531   return EFI_SUCCESS;
    532 }
    533