Synchronize EfiOpenFileByDevicePath() with the MdePkg/UefiLib instance, as described in the previous patch. Cc: Liming Gao <liming.gao@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Ruiyu Ni <ruiyu.ni@intel.com> Suggested-by: Ruiyu Ni <ruiyu.ni@intel.com> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=1074 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			1893 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1893 lines
		
	
	
		
			63 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   The UEFI Library provides functions and macros that simplify the development of
 | |
|   UEFI Drivers and UEFI Applications.  These functions and macros help manage EFI
 | |
|   events, build simple locks utilizing EFI Task Priority Levels (TPLs), install
 | |
|   EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers,
 | |
|   and print messages on the console output and standard error devices.
 | |
| 
 | |
|   Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| 
 | |
| #include "UefiLibInternal.h"
 | |
| 
 | |
| /**
 | |
|   Compare whether two names of languages are identical.
 | |
| 
 | |
|   @param  Language1 Name of language 1.
 | |
|   @param  Language2 Name of language 2.
 | |
| 
 | |
|   @retval TRUE      Language 1 and language 2 are the same.
 | |
|   @retval FALSE     Language 1 and language 2 are not the same.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| CompareIso639LanguageCode (
 | |
|   IN CONST CHAR8  *Language1,
 | |
|   IN CONST CHAR8  *Language2
 | |
|   )
 | |
| {
 | |
|   UINT32  Name1;
 | |
|   UINT32  Name2;
 | |
| 
 | |
|   Name1 = ReadUnaligned24 ((CONST UINT32 *) Language1);
 | |
|   Name2 = ReadUnaligned24 ((CONST UINT32 *) Language2);
 | |
| 
 | |
|   return (BOOLEAN) (Name1 == Name2);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrieves a pointer to the system configuration table from the EFI System Table
 | |
|   based on a specified GUID.
 | |
| 
 | |
|   This function searches the list of configuration tables stored in the EFI System Table
 | |
|   for a table with a GUID that matches TableGuid.  If a match is found, then a pointer to
 | |
|   the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID
 | |
|   is not found, then EFI_NOT_FOUND is returned.
 | |
|   If TableGuid is NULL, then ASSERT().
 | |
|   If Table is NULL, then ASSERT().
 | |
| 
 | |
|   @param  TableGuid       Pointer to table's GUID type..
 | |
|   @param  Table           Pointer to the table associated with TableGuid in the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS     A configuration table matching TableGuid was found.
 | |
|   @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiGetSystemConfigurationTable (
 | |
|   IN  EFI_GUID  *TableGuid,
 | |
|   OUT VOID      **Table
 | |
|   )
 | |
| {
 | |
|   EFI_SYSTEM_TABLE  *SystemTable;
 | |
|   UINTN             Index;
 | |
| 
 | |
|   ASSERT (TableGuid != NULL);
 | |
|   ASSERT (Table != NULL);
 | |
| 
 | |
|   SystemTable = gST;
 | |
|   *Table = NULL;
 | |
|   for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
 | |
|     if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
 | |
|       *Table = SystemTable->ConfigurationTable[Index].VendorTable;
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Creates and returns a notification event and registers that event with all the protocol
 | |
|   instances specified by ProtocolGuid.
 | |
| 
 | |
|   This function causes the notification function to be executed for every protocol of type
 | |
|   ProtocolGuid instance that exists in the system when this function is invoked. If there are
 | |
|   no instances of ProtocolGuid in the handle database at the time this function is invoked,
 | |
|   then the notification function is still executed one time. In addition, every time a protocol
 | |
|   of type ProtocolGuid instance is installed or reinstalled, the notification function is also
 | |
|   executed. This function returns the notification event that was created.
 | |
|   If ProtocolGuid is NULL, then ASSERT().
 | |
|   If NotifyTpl is not a legal TPL value, then ASSERT().
 | |
|   If NotifyFunction is NULL, then ASSERT().
 | |
|   If Registration is NULL, then ASSERT().
 | |
| 
 | |
| 
 | |
|   @param  ProtocolGuid    Supplies GUID of the protocol upon whose installation the event is fired.
 | |
|   @param  NotifyTpl       Supplies the task priority level of the event notifications.
 | |
|   @param  NotifyFunction  Supplies the function to notify when the event is signaled.
 | |
|   @param  NotifyContext   The context parameter to pass to NotifyFunction.
 | |
|   @param  Registration    A pointer to a memory location to receive the registration value.
 | |
|                           This value is passed to LocateHandle() to obtain new handles that
 | |
|                           have been added that support the ProtocolGuid-specified protocol.
 | |
| 
 | |
|   @return The notification event that was created.
 | |
| 
 | |
| **/
 | |
| EFI_EVENT
 | |
| EFIAPI
 | |
| EfiCreateProtocolNotifyEvent(
 | |
|   IN  EFI_GUID          *ProtocolGuid,
 | |
|   IN  EFI_TPL           NotifyTpl,
 | |
|   IN  EFI_EVENT_NOTIFY  NotifyFunction,
 | |
|   IN  VOID              *NotifyContext,  OPTIONAL
 | |
|   OUT VOID              **Registration
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_EVENT   Event;
 | |
| 
 | |
|   ASSERT (ProtocolGuid != NULL);
 | |
|   ASSERT (NotifyFunction != NULL);
 | |
|   ASSERT (Registration != NULL);
 | |
| 
 | |
|   //
 | |
|   // Create the event
 | |
|   //
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   NotifyTpl,
 | |
|                   NotifyFunction,
 | |
|                   NotifyContext,
 | |
|                   &Event
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Register for protocol notifications on this event
 | |
|   //
 | |
| 
 | |
|   Status = gBS->RegisterProtocolNotify (
 | |
|                   ProtocolGuid,
 | |
|                   Event,
 | |
|                   Registration
 | |
|                   );
 | |
| 
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Kick the event so we will perform an initial pass of
 | |
|   // current installed drivers
 | |
|   //
 | |
| 
 | |
|   gBS->SignalEvent (Event);
 | |
|   return Event;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Creates a named event that can be signaled with EfiNamedEventSignal().
 | |
| 
 | |
|   This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
 | |
|   This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
 | |
|   listeners on the same event named by the GUID specified by Name.
 | |
|   If Name is NULL, then ASSERT().
 | |
|   If NotifyTpl is not a legal TPL value, then ASSERT().
 | |
|   If NotifyFunction is NULL, then ASSERT().
 | |
| 
 | |
|   @param  Name                  Supplies GUID name of the event.
 | |
|   @param  NotifyTpl             Supplies the task priority level of the event notifications.
 | |
|   @param  NotifyFunction        Supplies the function to notify when the event is signaled.
 | |
|   @param  NotifyContext         The context parameter to pass to NotifyFunction.
 | |
|   @param  Registration          A pointer to a memory location to receive the registration value.
 | |
| 
 | |
|   @retval EFI_SUCCESS           A named event was created.
 | |
|   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to create the named event.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiNamedEventListen (
 | |
|   IN CONST EFI_GUID    *Name,
 | |
|   IN EFI_TPL           NotifyTpl,
 | |
|   IN EFI_EVENT_NOTIFY  NotifyFunction,
 | |
|   IN CONST VOID        *NotifyContext,  OPTIONAL
 | |
|   OUT VOID             *Registration OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_EVENT   Event;
 | |
|   VOID        *RegistrationLocal;
 | |
| 
 | |
|   ASSERT (Name != NULL);
 | |
|   ASSERT (NotifyFunction != NULL);
 | |
|   ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
 | |
| 
 | |
|   //
 | |
|   // Create event
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   NotifyTpl,
 | |
|                   NotifyFunction,
 | |
|                   (VOID *) NotifyContext,
 | |
|                   &Event
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // The Registration is not optional to RegisterProtocolNotify().
 | |
|   // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
 | |
|   //
 | |
|   if (Registration != NULL) {
 | |
|     RegistrationLocal = Registration;
 | |
|   } else {
 | |
|     RegistrationLocal = &RegistrationLocal;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Register for an installation of protocol interface
 | |
|   //
 | |
| 
 | |
|   Status = gBS->RegisterProtocolNotify (
 | |
|                   (EFI_GUID *) Name,
 | |
|                   Event,
 | |
|                   RegistrationLocal
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Signals a named event created with EfiNamedEventListen().
 | |
| 
 | |
|   This function signals the named event specified by Name. The named event must have been
 | |
|   created with EfiNamedEventListen().
 | |
|   If Name is NULL, then ASSERT().
 | |
| 
 | |
|   @param  Name                  Supplies GUID name of the event.
 | |
| 
 | |
|   @retval EFI_SUCCESS           A named event was signaled.
 | |
|   @retval EFI_OUT_OF_RESOURCES  There are not enough resource to signal the named event.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiNamedEventSignal (
 | |
|   IN CONST EFI_GUID  *Name
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_HANDLE  Handle;
 | |
| 
 | |
|   ASSERT(Name != NULL);
 | |
| 
 | |
|   Handle = NULL;
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &Handle,
 | |
|                   (EFI_GUID *) Name,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = gBS->UninstallProtocolInterface (
 | |
|                   Handle,
 | |
|                   (EFI_GUID *) Name,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Signals an event group by placing a new event in the group temporarily and
 | |
|   signaling it.
 | |
| 
 | |
|   @param[in] EventGroup          Supplies the unique identifier of the event
 | |
|                                  group to signal.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The event group was signaled successfully.
 | |
|   @retval EFI_INVALID_PARAMETER  EventGroup is NULL.
 | |
|   @return                        Error codes that report problems about event
 | |
|                                  creation or signaling.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiEventGroupSignal (
 | |
|   IN CONST EFI_GUID *EventGroup
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
|   EFI_EVENT  Event;
 | |
| 
 | |
|   if (EventGroup == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_CALLBACK,
 | |
|                   EfiEventEmptyFunction,
 | |
|                   NULL,
 | |
|                   EventGroup,
 | |
|                   &Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->SignalEvent (Event);
 | |
|   gBS->CloseEvent (Event);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   An empty function that can be used as NotifyFunction parameter of
 | |
|   CreateEvent() or CreateEventEx().
 | |
| 
 | |
|   @param Event              Event whose notification function is being invoked.
 | |
|   @param Context            The pointer to the notification function's context,
 | |
|                             which is implementation-dependent.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| EfiEventEmptyFunction (
 | |
|   IN EFI_EVENT              Event,
 | |
|   IN VOID                   *Context
 | |
|   )
 | |
| {
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns the current TPL.
 | |
| 
 | |
|   This function returns the current TPL.  There is no EFI service to directly
 | |
|   retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
 | |
|   the TPL to TPL_HIGH_LEVEL.  This will return the current TPL.  The TPL level
 | |
|   can then immediately be restored back to the current TPL level with a call
 | |
|   to RestoreTPL().
 | |
| 
 | |
|   @return The current TPL.
 | |
| 
 | |
| **/
 | |
| EFI_TPL
 | |
| EFIAPI
 | |
| EfiGetCurrentTpl (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_TPL Tpl;
 | |
| 
 | |
|   Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| 
 | |
|   return Tpl;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initializes a basic mutual exclusion lock.
 | |
| 
 | |
|   This function initializes a basic mutual exclusion lock to the released state
 | |
|   and returns the lock.  Each lock provides mutual exclusion access at its task
 | |
|   priority level.  Since there is no preemption or multiprocessor support in EFI,
 | |
|   acquiring the lock only consists of raising to the locks TPL.
 | |
|   If Lock is NULL, then ASSERT().
 | |
|   If Priority is not a valid TPL value, then ASSERT().
 | |
| 
 | |
|   @param  Lock       A pointer to the lock data structure to initialize.
 | |
|   @param  Priority   EFI TPL associated with the lock.
 | |
| 
 | |
|   @return The lock.
 | |
| 
 | |
| **/
 | |
| EFI_LOCK *
 | |
| EFIAPI
 | |
| EfiInitializeLock (
 | |
|   IN OUT EFI_LOCK  *Lock,
 | |
|   IN EFI_TPL        Priority
 | |
|   )
 | |
| {
 | |
|   ASSERT (Lock != NULL);
 | |
|   ASSERT (Priority <= TPL_HIGH_LEVEL);
 | |
| 
 | |
|   Lock->Tpl       = Priority;
 | |
|   Lock->OwnerTpl  = TPL_APPLICATION;
 | |
|   Lock->Lock      = EfiLockReleased ;
 | |
|   return Lock;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Acquires ownership of a lock.
 | |
| 
 | |
|   This function raises the system's current task priority level to the task
 | |
|   priority level of the mutual exclusion lock.  Then, it places the lock in the
 | |
|   acquired state.
 | |
|   If Lock is NULL, then ASSERT().
 | |
|   If Lock is not initialized, then ASSERT().
 | |
|   If Lock is already in the acquired state, then ASSERT().
 | |
| 
 | |
|   @param  Lock              A pointer to the lock to acquire.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| EfiAcquireLock (
 | |
|   IN EFI_LOCK  *Lock
 | |
|   )
 | |
| {
 | |
|   ASSERT (Lock != NULL);
 | |
|   ASSERT (Lock->Lock == EfiLockReleased);
 | |
| 
 | |
|   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
 | |
|   Lock->Lock     = EfiLockAcquired;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Acquires ownership of a lock.
 | |
| 
 | |
|   This function raises the system's current task priority level to the task priority
 | |
|   level of the mutual exclusion lock.  Then, it attempts to place the lock in the acquired state.
 | |
|   If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
 | |
|   Otherwise, EFI_SUCCESS is returned.
 | |
|   If Lock is NULL, then ASSERT().
 | |
|   If Lock is not initialized, then ASSERT().
 | |
| 
 | |
|   @param  Lock              A pointer to the lock to acquire.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The lock was acquired.
 | |
|   @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiAcquireLockOrFail (
 | |
|   IN EFI_LOCK  *Lock
 | |
|   )
 | |
| {
 | |
| 
 | |
|   ASSERT (Lock != NULL);
 | |
|   ASSERT (Lock->Lock != EfiLockUninitialized);
 | |
| 
 | |
|   if (Lock->Lock == EfiLockAcquired) {
 | |
|     //
 | |
|     // Lock is already owned, so bail out
 | |
|     //
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
 | |
| 
 | |
|   Lock->Lock = EfiLockAcquired;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Releases ownership of a lock.
 | |
| 
 | |
|   This function transitions a mutual exclusion lock from the acquired state to
 | |
|   the released state, and restores the system's task priority level to its
 | |
|   previous level.
 | |
|   If Lock is NULL, then ASSERT().
 | |
|   If Lock is not initialized, then ASSERT().
 | |
|   If Lock is already in the released state, then ASSERT().
 | |
| 
 | |
|   @param  Lock  A pointer to the lock to release.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| EfiReleaseLock (
 | |
|   IN EFI_LOCK  *Lock
 | |
|   )
 | |
| {
 | |
|   EFI_TPL Tpl;
 | |
| 
 | |
|   ASSERT (Lock != NULL);
 | |
|   ASSERT (Lock->Lock == EfiLockAcquired);
 | |
| 
 | |
|   Tpl = Lock->OwnerTpl;
 | |
| 
 | |
|   Lock->Lock = EfiLockReleased;
 | |
| 
 | |
|   gBS->RestoreTPL (Tpl);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Tests whether a controller handle is being managed by a specific driver.
 | |
| 
 | |
|   This function tests whether the driver specified by DriverBindingHandle is
 | |
|   currently managing the controller specified by ControllerHandle.  This test
 | |
|   is performed by evaluating if the the protocol specified by ProtocolGuid is
 | |
|   present on ControllerHandle and is was opened by DriverBindingHandle with an
 | |
|   attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
 | |
|   If ProtocolGuid is NULL, then ASSERT().
 | |
| 
 | |
|   @param  ControllerHandle     A handle for a controller to test.
 | |
|   @param  DriverBindingHandle  Specifies the driver binding handle for the
 | |
|                                driver.
 | |
|   @param  ProtocolGuid         Specifies the protocol that the driver specified
 | |
|                                by DriverBindingHandle opens in its Start()
 | |
|                                function.
 | |
| 
 | |
|   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
 | |
|                                specified by DriverBindingHandle.
 | |
|   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
 | |
|                                specified by DriverBindingHandle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiTestManagedDevice (
 | |
|   IN CONST EFI_HANDLE       ControllerHandle,
 | |
|   IN CONST EFI_HANDLE       DriverBindingHandle,
 | |
|   IN CONST EFI_GUID         *ProtocolGuid
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   VOID           *ManagedInterface;
 | |
| 
 | |
|   ASSERT (ProtocolGuid != NULL);
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   ControllerHandle,
 | |
|                   (EFI_GUID *) ProtocolGuid,
 | |
|                   &ManagedInterface,
 | |
|                   DriverBindingHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     gBS->CloseProtocol (
 | |
|            ControllerHandle,
 | |
|            (EFI_GUID *) ProtocolGuid,
 | |
|            DriverBindingHandle,
 | |
|            ControllerHandle
 | |
|            );
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (Status != EFI_ALREADY_STARTED) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Tests whether a child handle is a child device of the controller.
 | |
| 
 | |
|   This function tests whether ChildHandle is one of the children of
 | |
|   ControllerHandle.  This test is performed by checking to see if the protocol
 | |
|   specified by ProtocolGuid is present on ControllerHandle and opened by
 | |
|   ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
 | |
|   If ProtocolGuid is NULL, then ASSERT().
 | |
| 
 | |
|   @param  ControllerHandle     A handle for a (parent) controller to test.
 | |
|   @param  ChildHandle          A child handle to test.
 | |
|   @param  ProtocolGuid         Supplies the protocol that the child controller
 | |
|                                opens on its parent controller.
 | |
| 
 | |
|   @retval EFI_SUCCESS          ChildHandle is a child of the ControllerHandle.
 | |
|   @retval EFI_UNSUPPORTED      ChildHandle is not a child of the
 | |
|                                ControllerHandle.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiTestChildHandle (
 | |
|   IN CONST EFI_HANDLE       ControllerHandle,
 | |
|   IN CONST EFI_HANDLE       ChildHandle,
 | |
|   IN CONST EFI_GUID         *ProtocolGuid
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                            Status;
 | |
|   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY   *OpenInfoBuffer;
 | |
|   UINTN                                 EntryCount;
 | |
|   UINTN                                 Index;
 | |
| 
 | |
|   ASSERT (ProtocolGuid != NULL);
 | |
| 
 | |
|   //
 | |
|   // Retrieve the list of agents that are consuming the specific protocol
 | |
|   // on ControllerHandle.
 | |
|   //
 | |
|   Status = gBS->OpenProtocolInformation (
 | |
|                   ControllerHandle,
 | |
|                   (EFI_GUID *) ProtocolGuid,
 | |
|                   &OpenInfoBuffer,
 | |
|                   &EntryCount
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Inspect if ChildHandle is one of the agents.
 | |
|   //
 | |
|   Status = EFI_UNSUPPORTED;
 | |
|   for (Index = 0; Index < EntryCount; Index++) {
 | |
|     if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
 | |
|         (OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (OpenInfoBuffer);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function looks up a Unicode string in UnicodeStringTable.
 | |
| 
 | |
|   If Language is a member of SupportedLanguages and a Unicode string is found in
 | |
|   UnicodeStringTable that matches the language code specified by Language, then it
 | |
|   is returned in UnicodeString.
 | |
| 
 | |
|   @param  Language                A pointer to the ISO 639-2 language code for the
 | |
|                                   Unicode string to look up and return.
 | |
|   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
 | |
|                                   that the Unicode string table supports.  Language
 | |
|                                   must be a member of this set.
 | |
|   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
 | |
|   @param  UnicodeString           A pointer to the Unicode string from UnicodeStringTable
 | |
|                                   that matches the language specified by Language.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The Unicode string that matches the language
 | |
|                                   specified by Language was found
 | |
|                                   in the table of Unicode strings UnicodeStringTable,
 | |
|                                   and it was returned in UnicodeString.
 | |
|   @retval EFI_INVALID_PARAMETER   Language is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
 | |
|   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
 | |
|   @retval EFI_UNSUPPORTED         UnicodeStringTable is NULL.
 | |
|   @retval EFI_UNSUPPORTED         The language specified by Language is not a
 | |
|                                   member of SupportedLanguages.
 | |
|   @retval EFI_UNSUPPORTED         The language specified by Language is not
 | |
|                                   supported by UnicodeStringTable.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LookupUnicodeString (
 | |
|   IN CONST CHAR8                     *Language,
 | |
|   IN CONST CHAR8                     *SupportedLanguages,
 | |
|   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
 | |
|   OUT CHAR16                         **UnicodeString
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Make sure the parameters are valid
 | |
|   //
 | |
|   if (Language == NULL || UnicodeString == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If there are no supported languages, or the Unicode String Table is empty, then the
 | |
|   // Unicode String specified by Language is not supported by this Unicode String Table
 | |
|   //
 | |
|   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make sure Language is in the set of Supported Languages
 | |
|   //
 | |
|   while (*SupportedLanguages != 0) {
 | |
|     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
 | |
| 
 | |
|       //
 | |
|       // Search the Unicode String Table for the matching Language specifier
 | |
|       //
 | |
|       while (UnicodeStringTable->Language != NULL) {
 | |
|         if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
 | |
| 
 | |
|           //
 | |
|           // A matching string was found, so return it
 | |
|           //
 | |
|           *UnicodeString = UnicodeStringTable->UnicodeString;
 | |
|           return EFI_SUCCESS;
 | |
|         }
 | |
| 
 | |
|         UnicodeStringTable++;
 | |
|       }
 | |
| 
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     SupportedLanguages += 3;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function looks up a Unicode string in UnicodeStringTable.
 | |
| 
 | |
|   If Language is a member of SupportedLanguages and a Unicode string is found in
 | |
|   UnicodeStringTable that matches the language code specified by Language, then
 | |
|   it is returned in UnicodeString.
 | |
| 
 | |
|   @param  Language             A pointer to an ASCII string containing the ISO 639-2 or the
 | |
|                                RFC 4646 language code for the Unicode string to look up and
 | |
|                                return. If Iso639Language is TRUE, then this ASCII string is
 | |
|                                not assumed to be Null-terminated, and only the first three
 | |
|                                characters are used. If Iso639Language is FALSE, then this ASCII
 | |
|                                string must be Null-terminated.
 | |
|   @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that contains a
 | |
|                                set of ISO 639-2 or RFC 4646 language codes that the Unicode
 | |
|                                string table supports.  Language must be a member of this set.
 | |
|                                If Iso639Language is TRUE, then this string contains one or more
 | |
|                                ISO 639-2 language codes with no separator characters. If Iso639Language
 | |
|                                is FALSE, then is string contains one or more RFC 4646 language
 | |
|                                codes separated by ';'.
 | |
|   @param  UnicodeStringTable   A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
 | |
|                                is defined in "Related Definitions".
 | |
|   @param  UnicodeString        A pointer to the Null-terminated Unicode string from UnicodeStringTable
 | |
|                                that matches the language specified by Language.
 | |
|   @param  Iso639Language       Specifies the supported language code format. If it is TRUE, then
 | |
|                                Language and SupportedLanguages follow ISO 639-2 language code format.
 | |
|                                Otherwise, they follow RFC 4646 language code format.
 | |
| 
 | |
| 
 | |
|   @retval  EFI_SUCCESS            The Unicode string that matches the language specified by Language
 | |
|                                   was found in the table of Unicode strings UnicodeStringTable, and
 | |
|                                   it was returned in UnicodeString.
 | |
|   @retval  EFI_INVALID_PARAMETER  Language is NULL.
 | |
|   @retval  EFI_INVALID_PARAMETER  UnicodeString is NULL.
 | |
|   @retval  EFI_UNSUPPORTED        SupportedLanguages is NULL.
 | |
|   @retval  EFI_UNSUPPORTED        UnicodeStringTable is NULL.
 | |
|   @retval  EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
 | |
|   @retval  EFI_UNSUPPORTED        The language specified by Language is not supported by UnicodeStringTable.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LookupUnicodeString2 (
 | |
|   IN CONST CHAR8                     *Language,
 | |
|   IN CONST CHAR8                     *SupportedLanguages,
 | |
|   IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
 | |
|   OUT CHAR16                         **UnicodeString,
 | |
|   IN BOOLEAN                         Iso639Language
 | |
|   )
 | |
| {
 | |
|   BOOLEAN   Found;
 | |
|   UINTN     Index;
 | |
|   CHAR8     *LanguageString;
 | |
| 
 | |
|   //
 | |
|   // Make sure the parameters are valid
 | |
|   //
 | |
|   if (Language == NULL || UnicodeString == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If there are no supported languages, or the Unicode String Table is empty, then the
 | |
|   // Unicode String specified by Language is not supported by this Unicode String Table
 | |
|   //
 | |
|   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make sure Language is in the set of Supported Languages
 | |
|   //
 | |
|   Found = FALSE;
 | |
|   while (*SupportedLanguages != 0) {
 | |
|     if (Iso639Language) {
 | |
|       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
 | |
|         Found = TRUE;
 | |
|         break;
 | |
|       }
 | |
|       SupportedLanguages += 3;
 | |
|     } else {
 | |
|       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
 | |
|       if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
 | |
|         Found = TRUE;
 | |
|         break;
 | |
|       }
 | |
|       SupportedLanguages += Index;
 | |
|       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
 | |
|   //
 | |
|   if (!Found) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Search the Unicode String Table for the matching Language specifier
 | |
|   //
 | |
|   while (UnicodeStringTable->Language != NULL) {
 | |
|     LanguageString = UnicodeStringTable->Language;
 | |
|     while (0 != *LanguageString) {
 | |
|       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
 | |
|       if (AsciiStrnCmp(LanguageString, Language, Index) == 0) {
 | |
|         *UnicodeString = UnicodeStringTable->UnicodeString;
 | |
|         return EFI_SUCCESS;
 | |
|       }
 | |
|       LanguageString += Index;
 | |
|       for (Index = 0 ;LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++);
 | |
|     }
 | |
|     UnicodeStringTable++;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function adds a Unicode string to UnicodeStringTable.
 | |
| 
 | |
|   If Language is a member of SupportedLanguages then UnicodeString is added to
 | |
|   UnicodeStringTable.  New buffers are allocated for both Language and
 | |
|   UnicodeString.  The contents of Language and UnicodeString are copied into
 | |
|   these new buffers.  These buffers are automatically freed when
 | |
|   FreeUnicodeStringTable() is called.
 | |
| 
 | |
|   @param  Language                A pointer to the ISO 639-2 language code for the Unicode
 | |
|                                   string to add.
 | |
|   @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
 | |
|                                   that the Unicode string table supports.
 | |
|                                   Language must be a member of this set.
 | |
|   @param  UnicodeStringTable      A pointer to the table of Unicode strings.
 | |
|   @param  UnicodeString           A pointer to the Unicode string to add.
 | |
| 
 | |
|   @retval EFI_SUCCESS             The Unicode string that matches the language
 | |
|                                   specified by Language was found in the table of
 | |
|                                   Unicode strings UnicodeStringTable, and it was
 | |
|                                   returned in UnicodeString.
 | |
|   @retval EFI_INVALID_PARAMETER   Language is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER   UnicodeString is an empty string.
 | |
|   @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
 | |
|   @retval EFI_ALREADY_STARTED     A Unicode string with language Language is
 | |
|                                   already present in UnicodeStringTable.
 | |
|   @retval EFI_OUT_OF_RESOURCES    There is not enough memory to add another
 | |
|                                   Unicode string to UnicodeStringTable.
 | |
|   @retval EFI_UNSUPPORTED         The language specified by Language is not a
 | |
|                                   member of SupportedLanguages.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AddUnicodeString (
 | |
|   IN     CONST CHAR8               *Language,
 | |
|   IN     CONST CHAR8               *SupportedLanguages,
 | |
|   IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
 | |
|   IN     CONST CHAR16              *UnicodeString
 | |
|   )
 | |
| {
 | |
|   UINTN                     NumberOfEntries;
 | |
|   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
 | |
|   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
 | |
|   UINTN                     UnicodeStringLength;
 | |
| 
 | |
|   //
 | |
|   // Make sure the parameter are valid
 | |
|   //
 | |
|   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If there are no supported languages, then a Unicode String can not be added
 | |
|   //
 | |
|   if (SupportedLanguages == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the Unicode String is empty, then a Unicode String can not be added
 | |
|   //
 | |
|   if (UnicodeString[0] == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make sure Language is a member of SupportedLanguages
 | |
|   //
 | |
|   while (*SupportedLanguages != 0) {
 | |
|     if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
 | |
| 
 | |
|       //
 | |
|       // Determine the size of the Unicode String Table by looking for a NULL Language entry
 | |
|       //
 | |
|       NumberOfEntries = 0;
 | |
|       if (*UnicodeStringTable != NULL) {
 | |
|         OldUnicodeStringTable = *UnicodeStringTable;
 | |
|         while (OldUnicodeStringTable->Language != NULL) {
 | |
|           if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
 | |
|             return EFI_ALREADY_STARTED;
 | |
|           }
 | |
| 
 | |
|           OldUnicodeStringTable++;
 | |
|           NumberOfEntries++;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Allocate space for a new Unicode String Table.  It must hold the current number of
 | |
|       // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
 | |
|       // marker
 | |
|       //
 | |
|       NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
 | |
|       if (NewUnicodeStringTable == NULL) {
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // If the current Unicode String Table contains any entries, then copy them to the
 | |
|       // newly allocated Unicode String Table.
 | |
|       //
 | |
|       if (*UnicodeStringTable != NULL) {
 | |
|         CopyMem (
 | |
|            NewUnicodeStringTable,
 | |
|            *UnicodeStringTable,
 | |
|            NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
 | |
|            );
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Allocate space for a copy of the Language specifier
 | |
|       //
 | |
|       NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
 | |
|       if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
 | |
|         gBS->FreePool (NewUnicodeStringTable);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Compute the length of the Unicode String
 | |
|       //
 | |
|       for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
 | |
|         ;
 | |
| 
 | |
|       //
 | |
|       // Allocate space for a copy of the Unicode String
 | |
|       //
 | |
|       NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
 | |
|                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
 | |
|                                                               UnicodeString
 | |
|                                                               );
 | |
|       if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
 | |
|         gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
 | |
|         gBS->FreePool (NewUnicodeStringTable);
 | |
|         return EFI_OUT_OF_RESOURCES;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Mark the end of the Unicode String Table
 | |
|       //
 | |
|       NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
 | |
|       NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
 | |
| 
 | |
|       //
 | |
|       // Free the old Unicode String Table
 | |
|       //
 | |
|       if (*UnicodeStringTable != NULL) {
 | |
|         gBS->FreePool (*UnicodeStringTable);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Point UnicodeStringTable at the newly allocated Unicode String Table
 | |
|       //
 | |
|       *UnicodeStringTable = NewUnicodeStringTable;
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     SupportedLanguages += 3;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function adds the Null-terminated Unicode string specified by UnicodeString
 | |
|   to UnicodeStringTable.
 | |
| 
 | |
|   If Language is a member of SupportedLanguages then UnicodeString is added to
 | |
|   UnicodeStringTable.  New buffers are allocated for both Language and UnicodeString.
 | |
|   The contents of Language and UnicodeString are copied into these new buffers.
 | |
|   These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
 | |
| 
 | |
|   @param  Language            A pointer to an ASCII string containing the ISO 639-2 or
 | |
|                               the RFC 4646 language code for the Unicode string to add.
 | |
|                               If Iso639Language is TRUE, then this ASCII string is not
 | |
|                               assumed to be Null-terminated, and only the first three
 | |
|                               chacters are used. If Iso639Language is FALSE, then this
 | |
|                               ASCII string must be Null-terminated.
 | |
|   @param  SupportedLanguages  A pointer to a Null-terminated ASCII string that contains
 | |
|                               a set of ISO 639-2 or RFC 4646 language codes that the Unicode
 | |
|                               string table supports.  Language must be a member of this set.
 | |
|                               If Iso639Language is TRUE, then this string contains one or more
 | |
|                               ISO 639-2 language codes with no separator characters.
 | |
|                               If Iso639Language is FALSE, then is string contains one or more
 | |
|                               RFC 4646 language codes separated by ';'.
 | |
|   @param  UnicodeStringTable  A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
 | |
|                               is defined in "Related Definitions".
 | |
|   @param  UnicodeString       A pointer to the Unicode string to add.
 | |
|   @param  Iso639Language      Specifies the supported language code format. If it is TRUE,
 | |
|                               then Language and SupportedLanguages follow ISO 639-2 language code format.
 | |
|                               Otherwise, they follow RFC 4646 language code format.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The Unicode string that matches the language specified by
 | |
|                                  Language was found in the table of Unicode strings UnicodeStringTable,
 | |
|                                  and it was returned in UnicodeString.
 | |
|   @retval EFI_INVALID_PARAMETER  Language is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER  UnicodeString is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER  UnicodeString is an empty string.
 | |
|   @retval EFI_UNSUPPORTED        SupportedLanguages is NULL.
 | |
|   @retval EFI_ALREADY_STARTED    A Unicode string with language Language is already present in
 | |
|                                  UnicodeStringTable.
 | |
|   @retval EFI_OUT_OF_RESOURCES   There is not enough memory to add another Unicode string UnicodeStringTable.
 | |
|   @retval EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AddUnicodeString2 (
 | |
|   IN     CONST CHAR8               *Language,
 | |
|   IN     CONST CHAR8               *SupportedLanguages,
 | |
|   IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
 | |
|   IN     CONST CHAR16              *UnicodeString,
 | |
|   IN     BOOLEAN                   Iso639Language
 | |
|   )
 | |
| {
 | |
|   UINTN                     NumberOfEntries;
 | |
|   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
 | |
|   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
 | |
|   UINTN                     UnicodeStringLength;
 | |
|   BOOLEAN                   Found;
 | |
|   UINTN                     Index;
 | |
|   CHAR8                     *LanguageString;
 | |
| 
 | |
|   //
 | |
|   // Make sure the parameter are valid
 | |
|   //
 | |
|   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If there are no supported languages, then a Unicode String can not be added
 | |
|   //
 | |
|   if (SupportedLanguages == NULL) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the Unicode String is empty, then a Unicode String can not be added
 | |
|   //
 | |
|   if (UnicodeString[0] == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make sure Language is a member of SupportedLanguages
 | |
|   //
 | |
|   Found = FALSE;
 | |
|   while (*SupportedLanguages != 0) {
 | |
|     if (Iso639Language) {
 | |
|       if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
 | |
|         Found = TRUE;
 | |
|         break;
 | |
|       }
 | |
|       SupportedLanguages += 3;
 | |
|     } else {
 | |
|       for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
 | |
|       if (AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) {
 | |
|         Found = TRUE;
 | |
|         break;
 | |
|       }
 | |
|       SupportedLanguages += Index;
 | |
|       for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
 | |
|   //
 | |
|   if (!Found) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Determine the size of the Unicode String Table by looking for a NULL Language entry
 | |
|   //
 | |
|   NumberOfEntries = 0;
 | |
|   if (*UnicodeStringTable != NULL) {
 | |
|     OldUnicodeStringTable = *UnicodeStringTable;
 | |
|     while (OldUnicodeStringTable->Language != NULL) {
 | |
|       LanguageString = OldUnicodeStringTable->Language;
 | |
| 
 | |
|       while (*LanguageString != 0) {
 | |
|         for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++);
 | |
| 
 | |
|         if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
 | |
|           return EFI_ALREADY_STARTED;
 | |
|         }
 | |
|         LanguageString += Index;
 | |
|         for (; *LanguageString != 0 && *LanguageString == ';'; LanguageString++);
 | |
|       }
 | |
|       OldUnicodeStringTable++;
 | |
|       NumberOfEntries++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate space for a new Unicode String Table.  It must hold the current number of
 | |
|   // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
 | |
|   // marker
 | |
|   //
 | |
|   NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
 | |
|   if (NewUnicodeStringTable == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the current Unicode String Table contains any entries, then copy them to the
 | |
|   // newly allocated Unicode String Table.
 | |
|   //
 | |
|   if (*UnicodeStringTable != NULL) {
 | |
|     CopyMem (
 | |
|       NewUnicodeStringTable,
 | |
|       *UnicodeStringTable,
 | |
|       NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate space for a copy of the Language specifier
 | |
|   //
 | |
|   NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize(Language), Language);
 | |
|   if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
 | |
|     gBS->FreePool (NewUnicodeStringTable);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Compute the length of the Unicode String
 | |
|   //
 | |
|   for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++);
 | |
| 
 | |
|   //
 | |
|   // Allocate space for a copy of the Unicode String
 | |
|   //
 | |
|   NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
 | |
|   if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
 | |
|     gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
 | |
|     gBS->FreePool (NewUnicodeStringTable);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Mark the end of the Unicode String Table
 | |
|   //
 | |
|   NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
 | |
|   NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
 | |
| 
 | |
|   //
 | |
|   // Free the old Unicode String Table
 | |
|   //
 | |
|   if (*UnicodeStringTable != NULL) {
 | |
|     gBS->FreePool (*UnicodeStringTable);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Point UnicodeStringTable at the newly allocated Unicode String Table
 | |
|   //
 | |
|   *UnicodeStringTable = NewUnicodeStringTable;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function frees the table of Unicode strings in UnicodeStringTable.
 | |
| 
 | |
|   If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
 | |
|   Otherwise, each language code, and each Unicode string in the Unicode string
 | |
|   table are freed, and EFI_SUCCESS is returned.
 | |
| 
 | |
|   @param  UnicodeStringTable  A pointer to the table of Unicode strings.
 | |
| 
 | |
|   @retval EFI_SUCCESS         The Unicode string table was freed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| FreeUnicodeStringTable (
 | |
|   IN EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
 | |
|   )
 | |
| {
 | |
|   UINTN Index;
 | |
| 
 | |
|   //
 | |
|   // If the Unicode String Table is NULL, then it is already freed
 | |
|   //
 | |
|   if (UnicodeStringTable == NULL) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Loop through the Unicode String Table until we reach the end of table marker
 | |
|   //
 | |
|   for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
 | |
| 
 | |
|     //
 | |
|     // Free the Language string from the Unicode String Table
 | |
|     //
 | |
|     gBS->FreePool (UnicodeStringTable[Index].Language);
 | |
| 
 | |
|     //
 | |
|     // Free the Unicode String from the Unicode String Table
 | |
|     //
 | |
|     if (UnicodeStringTable[Index].UnicodeString != NULL) {
 | |
|       gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free the Unicode String Table itself
 | |
|   //
 | |
|   gBS->FreePool (UnicodeStringTable);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns a pointer to an allocated buffer that contains the contents of a
 | |
|   variable retrieved through the UEFI Runtime Service GetVariable().  The
 | |
|   returned buffer is allocated using AllocatePool().  The caller is responsible
 | |
|   for freeing this buffer with FreePool().
 | |
| 
 | |
|   If Name is NULL, then ASSERT().
 | |
|   If Guid is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  Name  Pointer to a Null-terminated Unicode string.
 | |
|   @param[in]  Guid  Pointer to an EFI_GUID structure
 | |
| 
 | |
|   @retval NULL   The variable could not be retrieved.
 | |
|   @retval NULL   There are not enough resources available for the variable contents.
 | |
|   @retval Other  A pointer to allocated buffer containing the variable contents.
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EFIAPI
 | |
| GetVariable (
 | |
|   IN CONST CHAR16    *Name,
 | |
|   IN CONST EFI_GUID  *Guid
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       Size;
 | |
|   VOID        *Value;
 | |
| 
 | |
|   ASSERT (Name != NULL);
 | |
|   ASSERT (Guid != NULL);
 | |
| 
 | |
|   //
 | |
|   // Try to get the variable size.
 | |
|   //
 | |
|   Value = NULL;
 | |
|   Size = 0;
 | |
|   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer to get the variable.
 | |
|   //
 | |
|   Value = AllocatePool (Size);
 | |
|   if (Value == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the variable data.
 | |
|   //
 | |
|   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &Size, Value);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool(Value);
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Returns a pointer to an allocated buffer that contains the contents of a
 | |
|   variable retrieved through the UEFI Runtime Service GetVariable().  This
 | |
|   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
 | |
|   The returned buffer is allocated using AllocatePool().  The caller is
 | |
|   responsible for freeing this buffer with FreePool().
 | |
| 
 | |
|   If Name is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  Name  Pointer to a Null-terminated Unicode string.
 | |
| 
 | |
|   @retval NULL   The variable could not be retrieved.
 | |
|   @retval NULL   There are not enough resources available for the variable contents.
 | |
|   @retval Other  A pointer to allocated buffer containing the variable contents.
 | |
| 
 | |
| **/
 | |
| VOID *
 | |
| EFIAPI
 | |
| GetEfiGlobalVariable (
 | |
|   IN CONST CHAR16  *Name
 | |
|   )
 | |
| {
 | |
|   return GetVariable (Name, &gEfiGlobalVariableGuid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns the status whether get the variable success. The function retrieves
 | |
|   variable  through the UEFI Runtime Service GetVariable().  The
 | |
|   returned buffer is allocated using AllocatePool().  The caller is responsible
 | |
|   for freeing this buffer with FreePool().
 | |
| 
 | |
|   If Name  is NULL, then ASSERT().
 | |
|   If Guid  is NULL, then ASSERT().
 | |
|   If Value is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  Name  The pointer to a Null-terminated Unicode string.
 | |
|   @param[in]  Guid  The pointer to an EFI_GUID structure
 | |
|   @param[out] Value The buffer point saved the variable info.
 | |
|   @param[out] Size  The buffer size of the variable.
 | |
| 
 | |
|   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
 | |
|   @return EFI_SUCCESS               Find the specified variable.
 | |
|   @return Others Errors             Return errors from call to gRT->GetVariable.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetVariable2 (
 | |
|   IN CONST CHAR16    *Name,
 | |
|   IN CONST EFI_GUID  *Guid,
 | |
|   OUT VOID           **Value,
 | |
|   OUT UINTN          *Size OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       BufferSize;
 | |
| 
 | |
|   ASSERT (Name != NULL && Guid != NULL && Value != NULL);
 | |
| 
 | |
|   //
 | |
|   // Try to get the variable size.
 | |
|   //
 | |
|   BufferSize = 0;
 | |
|   *Value     = NULL;
 | |
|   if (Size != NULL) {
 | |
|     *Size  = 0;
 | |
|   }
 | |
| 
 | |
|   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate buffer to get the variable.
 | |
|   //
 | |
|   *Value = AllocatePool (BufferSize);
 | |
|   ASSERT (*Value != NULL);
 | |
|   if (*Value == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the variable data.
 | |
|   //
 | |
|   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool(*Value);
 | |
|     *Value = NULL;
 | |
|   }
 | |
| 
 | |
|   if (Size != NULL) {
 | |
|     *Size = BufferSize;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns a pointer to an allocated buffer that contains the contents of a
 | |
|   variable retrieved through the UEFI Runtime Service GetVariable().  This
 | |
|   function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
 | |
|   The returned buffer is allocated using AllocatePool().  The caller is
 | |
|   responsible for freeing this buffer with FreePool().
 | |
| 
 | |
|   If Name is NULL, then ASSERT().
 | |
|   If Value is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  Name  The pointer to a Null-terminated Unicode string.
 | |
|   @param[out] Value The buffer point saved the variable info.
 | |
|   @param[out] Size  The buffer size of the variable.
 | |
| 
 | |
|   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
 | |
|   @return EFI_SUCCESS               Find the specified variable.
 | |
|   @return Others Errors             Return errors from call to gRT->GetVariable.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetEfiGlobalVariable2 (
 | |
|   IN CONST CHAR16    *Name,
 | |
|   OUT VOID           **Value,
 | |
|   OUT UINTN          *Size OPTIONAL
 | |
|   )
 | |
| {
 | |
|   return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns a pointer to an allocated buffer that contains the best matching language
 | |
|   from a set of supported languages.
 | |
| 
 | |
|   This function supports both ISO 639-2 and RFC 4646 language codes, but language
 | |
|   code types may not be mixed in a single call to this function.  The language
 | |
|   code returned is allocated using AllocatePool().  The caller is responsible for
 | |
|   freeing the allocated buffer using FreePool().  This function supports a variable
 | |
|   argument list that allows the caller to pass in a prioritized list of language
 | |
|   codes to test against all the language codes in SupportedLanguages.
 | |
| 
 | |
|   If SupportedLanguages is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
 | |
|                                   contains a set of language codes in the format
 | |
|                                   specified by Iso639Language.
 | |
|   @param[in]  Iso639Language      If not zero, then all language codes are assumed to be
 | |
|                                   in ISO 639-2 format.  If zero, then all language
 | |
|                                   codes are assumed to be in RFC 4646 language format
 | |
|   @param[in]  ...                 A variable argument list that contains pointers to
 | |
|                                   Null-terminated ASCII strings that contain one or more
 | |
|                                   language codes in the format specified by Iso639Language.
 | |
|                                   The first language code from each of these language
 | |
|                                   code lists is used to determine if it is an exact or
 | |
|                                   close match to any of the language codes in
 | |
|                                   SupportedLanguages.  Close matches only apply to RFC 4646
 | |
|                                   language codes, and the matching algorithm from RFC 4647
 | |
|                                   is used to determine if a close match is present.  If
 | |
|                                   an exact or close match is found, then the matching
 | |
|                                   language code from SupportedLanguages is returned.  If
 | |
|                                   no matches are found, then the next variable argument
 | |
|                                   parameter is evaluated.  The variable argument list
 | |
|                                   is terminated by a NULL.
 | |
| 
 | |
|   @retval NULL   The best matching language could not be found in SupportedLanguages.
 | |
|   @retval NULL   There are not enough resources available to return the best matching
 | |
|                  language.
 | |
|   @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
 | |
|                  language in SupportedLanguages.
 | |
| 
 | |
| **/
 | |
| CHAR8 *
 | |
| EFIAPI
 | |
| GetBestLanguage (
 | |
|   IN CONST CHAR8  *SupportedLanguages,
 | |
|   IN UINTN        Iso639Language,
 | |
|   ...
 | |
|   )
 | |
| {
 | |
|   VA_LIST      Args;
 | |
|   CHAR8        *Language;
 | |
|   UINTN        CompareLength;
 | |
|   UINTN        LanguageLength;
 | |
|   CONST CHAR8  *Supported;
 | |
|   CHAR8        *BestLanguage;
 | |
| 
 | |
|   ASSERT (SupportedLanguages != NULL);
 | |
| 
 | |
|   VA_START (Args, Iso639Language);
 | |
|   while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
 | |
|     //
 | |
|     // Default to ISO 639-2 mode
 | |
|     //
 | |
|     CompareLength  = 3;
 | |
|     LanguageLength = MIN (3, AsciiStrLen (Language));
 | |
| 
 | |
|     //
 | |
|     // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
 | |
|     //
 | |
|     if (Iso639Language == 0) {
 | |
|       for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Trim back the length of Language used until it is empty
 | |
|     //
 | |
|     while (LanguageLength > 0) {
 | |
|       //
 | |
|       // Loop through all language codes in SupportedLanguages
 | |
|       //
 | |
|       for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
 | |
|         //
 | |
|         // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
 | |
|         //
 | |
|         if (Iso639Language == 0) {
 | |
|           //
 | |
|           // Skip ';' characters in Supported
 | |
|           //
 | |
|           for (; *Supported != '\0' && *Supported == ';'; Supported++);
 | |
|           //
 | |
|           // Determine the length of the next language code in Supported
 | |
|           //
 | |
|           for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
 | |
|           //
 | |
|           // If Language is longer than the Supported, then skip to the next language
 | |
|           //
 | |
|           if (LanguageLength > CompareLength) {
 | |
|             continue;
 | |
|           }
 | |
|         }
 | |
|         //
 | |
|         // See if the first LanguageLength characters in Supported match Language
 | |
|         //
 | |
|         if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
 | |
|           VA_END (Args);
 | |
|           //
 | |
|           // Allocate, copy, and return the best matching language code from SupportedLanguages
 | |
|           //
 | |
|           BestLanguage = AllocateZeroPool (CompareLength + 1);
 | |
|           if (BestLanguage == NULL) {
 | |
|             return NULL;
 | |
|           }
 | |
|           return CopyMem (BestLanguage, Supported, CompareLength);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Iso639Language != 0) {
 | |
|         //
 | |
|         // If ISO 639 mode, then each language can only be tested once
 | |
|         //
 | |
|         LanguageLength = 0;
 | |
|       } else {
 | |
|         //
 | |
|         // If RFC 4646 mode, then trim Language from the right to the next '-' character
 | |
|         //
 | |
|         for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   VA_END (Args);
 | |
| 
 | |
|   //
 | |
|   // No matches were found
 | |
|   //
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Returns an array of protocol instance that matches the given protocol.
 | |
| 
 | |
|   @param[in]  Protocol      Provides the protocol to search for.
 | |
|   @param[out] NoProtocols   The number of protocols returned in Buffer.
 | |
|   @param[out] Buffer        A pointer to the buffer to return the requested
 | |
|                             array of protocol instances that match Protocol.
 | |
|                             The returned buffer is allocated using
 | |
|                             EFI_BOOT_SERVICES.AllocatePool().  The caller is
 | |
|                             responsible for freeing this buffer with
 | |
|                             EFI_BOOT_SERVICES.FreePool().
 | |
| 
 | |
|   @retval EFI_SUCCESS            The array of protocols was returned in Buffer,
 | |
|                                  and the number of protocols in Buffer was
 | |
|                                  returned in NoProtocols.
 | |
|   @retval EFI_NOT_FOUND          No protocols found.
 | |
|   @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the
 | |
|                                  matching results.
 | |
|   @retval EFI_INVALID_PARAMETER  Protocol is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER  NoProtocols is NULL.
 | |
|   @retval EFI_INVALID_PARAMETER  Buffer is NULL.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiLocateProtocolBuffer (
 | |
|   IN  EFI_GUID  *Protocol,
 | |
|   OUT UINTN     *NoProtocols,
 | |
|   OUT VOID      ***Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINTN       NoHandles;
 | |
|   EFI_HANDLE  *HandleBuffer;
 | |
|   UINTN       Index;
 | |
| 
 | |
|   //
 | |
|   // Check input parameters
 | |
|   //
 | |
|   if (Protocol == NULL || NoProtocols == NULL || Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialze output parameters
 | |
|   //
 | |
|   *NoProtocols = 0;
 | |
|   *Buffer = NULL;
 | |
| 
 | |
|   //
 | |
|   // Retrieve the array of handles that support Protocol
 | |
|   //
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   Protocol,
 | |
|                   NULL,
 | |
|                   &NoHandles,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate array of protocol instances
 | |
|   //
 | |
|   Status = gBS->AllocatePool (
 | |
|                   EfiBootServicesData,
 | |
|                   NoHandles * sizeof (VOID *),
 | |
|                   (VOID **)Buffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Free the handle buffer
 | |
|     //
 | |
|     gBS->FreePool (HandleBuffer);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   ZeroMem (*Buffer, NoHandles * sizeof (VOID *));
 | |
| 
 | |
|   //
 | |
|   // Lookup Protocol on each handle in HandleBuffer to fill in the array of
 | |
|   // protocol instances.  Handle case where protocol instance was present when
 | |
|   // LocateHandleBuffer() was called, but is not present when HandleProtocol()
 | |
|   // is called.
 | |
|   //
 | |
|   for (Index = 0, *NoProtocols = 0; Index < NoHandles; Index++) {
 | |
|     Status = gBS->HandleProtocol (
 | |
|                     HandleBuffer[Index],
 | |
|                     Protocol,
 | |
|                     &((*Buffer)[*NoProtocols])
 | |
|                     );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       (*NoProtocols)++;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Free the handle buffer
 | |
|   //
 | |
|   gBS->FreePool (HandleBuffer);
 | |
| 
 | |
|   //
 | |
|   // Make sure at least one protocol instance was found
 | |
|   //
 | |
|   if (*NoProtocols == 0) {
 | |
|     gBS->FreePool (*Buffer);
 | |
|     *Buffer = NULL;
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Open or create a file or directory, possibly creating the chain of
 | |
|   directories leading up to the directory.
 | |
| 
 | |
|   EfiOpenFileByDevicePath() first locates EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on
 | |
|   FilePath, and opens the root directory of that filesystem with
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume().
 | |
| 
 | |
|   On the remaining device path, the longest initial sequence of
 | |
|   FILEPATH_DEVICE_PATH nodes is node-wise traversed with
 | |
|   EFI_FILE_PROTOCOL.Open().
 | |
| 
 | |
|   (As a consequence, if OpenMode includes EFI_FILE_MODE_CREATE, and Attributes
 | |
|   includes EFI_FILE_DIRECTORY, and each FILEPATH_DEVICE_PATH specifies a single
 | |
|   pathname component, then EfiOpenFileByDevicePath() ensures that the specified
 | |
|   series of subdirectories exist on return.)
 | |
| 
 | |
|   The EFI_FILE_PROTOCOL identified by the last FILEPATH_DEVICE_PATH node is
 | |
|   output to the caller; intermediate EFI_FILE_PROTOCOL instances are closed. If
 | |
|   there are no FILEPATH_DEVICE_PATH nodes past the node that identifies the
 | |
|   filesystem, then the EFI_FILE_PROTOCOL of the root directory of the
 | |
|   filesystem is output to the caller. If a device path node that is different
 | |
|   from FILEPATH_DEVICE_PATH is encountered relative to the filesystem, the
 | |
|   traversal is stopped with an error, and a NULL EFI_FILE_PROTOCOL is output.
 | |
| 
 | |
|   @param[in,out] FilePath  On input, the device path to the file or directory
 | |
|                            to open or create. The caller is responsible for
 | |
|                            ensuring that the device path pointed-to by FilePath
 | |
|                            is well-formed. On output, FilePath points one past
 | |
|                            the last node in the original device path that has
 | |
|                            been successfully processed. FilePath is set on
 | |
|                            output even if EfiOpenFileByDevicePath() returns an
 | |
|                            error.
 | |
| 
 | |
|   @param[out] File         On error, File is set to NULL. On success, File is
 | |
|                            set to the EFI_FILE_PROTOCOL of the root directory
 | |
|                            of the filesystem, if there are no
 | |
|                            FILEPATH_DEVICE_PATH nodes in FilePath; otherwise,
 | |
|                            File is set to the EFI_FILE_PROTOCOL identified by
 | |
|                            the last node in FilePath.
 | |
| 
 | |
|   @param[in] OpenMode      The OpenMode parameter to pass to
 | |
|                            EFI_FILE_PROTOCOL.Open().
 | |
| 
 | |
|   @param[in] Attributes    The Attributes parameter to pass to
 | |
|                            EFI_FILE_PROTOCOL.Open().
 | |
| 
 | |
|   @retval EFI_SUCCESS            The file or directory has been opened or
 | |
|                                  created.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  FilePath is NULL; or File is NULL; or FilePath
 | |
|                                  contains a device path node, past the node
 | |
|                                  that identifies
 | |
|                                  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, that is not a
 | |
|                                  FILEPATH_DEVICE_PATH node.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
 | |
| 
 | |
|   @return                        Error codes propagated from the
 | |
|                                  LocateDevicePath() and OpenProtocol() boot
 | |
|                                  services, and from the
 | |
|                                  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume()
 | |
|                                  and EFI_FILE_PROTOCOL.Open() member functions.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EfiOpenFileByDevicePath (
 | |
|   IN OUT EFI_DEVICE_PATH_PROTOCOL  **FilePath,
 | |
|   OUT    EFI_FILE_PROTOCOL         **File,
 | |
|   IN     UINT64                    OpenMode,
 | |
|   IN     UINT64                    Attributes
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   EFI_HANDLE                      FileSystemHandle;
 | |
|   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
 | |
|   EFI_FILE_PROTOCOL               *LastFile;
 | |
|   FILEPATH_DEVICE_PATH            *FilePathNode;
 | |
|   CHAR16                          *AlignedPathName;
 | |
|   CHAR16                          *PathName;
 | |
|   EFI_FILE_PROTOCOL               *NextFile;
 | |
| 
 | |
|   if (File == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   *File = NULL;
 | |
| 
 | |
|   if (FilePath == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Look up the filesystem.
 | |
|   //
 | |
|   Status = gBS->LocateDevicePath (
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   FilePath,
 | |
|                   &FileSystemHandle
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   FileSystemHandle,
 | |
|                   &gEfiSimpleFileSystemProtocolGuid,
 | |
|                   (VOID **)&FileSystem,
 | |
|                   gImageHandle,
 | |
|                   NULL,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the root directory of the filesystem. After this operation succeeds,
 | |
|   // we have to release LastFile on error.
 | |
|   //
 | |
|   Status = FileSystem->OpenVolume (FileSystem, &LastFile);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Traverse the device path nodes relative to the filesystem.
 | |
|   //
 | |
|   while (!IsDevicePathEnd (*FilePath)) {
 | |
|     if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
 | |
|         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto CloseLastFile;
 | |
|     }
 | |
|     FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath;
 | |
| 
 | |
|     //
 | |
|     // FilePathNode->PathName may be unaligned, and the UEFI specification
 | |
|     // requires pointers that are passed to protocol member functions to be
 | |
|     // aligned. Create an aligned copy of the pathname if necessary.
 | |
|     //
 | |
|     if ((UINTN)FilePathNode->PathName % sizeof *FilePathNode->PathName == 0) {
 | |
|       AlignedPathName = NULL;
 | |
|       PathName = FilePathNode->PathName;
 | |
|     } else {
 | |
|       AlignedPathName = AllocateCopyPool (
 | |
|                           (DevicePathNodeLength (FilePathNode) -
 | |
|                            SIZE_OF_FILEPATH_DEVICE_PATH),
 | |
|                           FilePathNode->PathName
 | |
|                           );
 | |
|       if (AlignedPathName == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto CloseLastFile;
 | |
|       }
 | |
|       PathName = AlignedPathName;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Open or create the file corresponding to the next pathname fragment.
 | |
|     //
 | |
|     Status = LastFile->Open (
 | |
|                          LastFile,
 | |
|                          &NextFile,
 | |
|                          PathName,
 | |
|                          OpenMode,
 | |
|                          Attributes
 | |
|                          );
 | |
| 
 | |
|     //
 | |
|     // Release any AlignedPathName on both error and success paths; PathName is
 | |
|     // no longer needed.
 | |
|     //
 | |
|     if (AlignedPathName != NULL) {
 | |
|       FreePool (AlignedPathName);
 | |
|     }
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto CloseLastFile;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Advance to the next device path node.
 | |
|     //
 | |
|     LastFile->Close (LastFile);
 | |
|     LastFile = NextFile;
 | |
|     *FilePath = NextDevicePathNode (FilePathNode);
 | |
|   }
 | |
| 
 | |
|   *File = LastFile;
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| CloseLastFile:
 | |
|   LastFile->Close (LastFile);
 | |
| 
 | |
|   //
 | |
|   // We are on the error path; we must have set an error Status for returning
 | |
|   // to the caller.
 | |
|   //
 | |
|   ASSERT (EFI_ERROR (Status));
 | |
|   return Status;
 | |
| }
 |