mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-24 16:27:42 +01:00
f45e1fdb5c
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
2037 lines
66 KiB
C
2037 lines
66 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>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
|
|
#include "UefiLibInternal.h"
|
|
|
|
/**
|
|
Empty constructor function that is required to resolve dependencies between
|
|
libraries.
|
|
|
|
** DO NOT REMOVE **
|
|
|
|
@param ImageHandle The firmware allocated handle for the EFI image.
|
|
@param SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The constructor executed correctly.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UefiLibConstructor (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
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 The pointer to table's GUID type.
|
|
@param Table The 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);
|
|
if (EFI_ERROR(Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Register for protocol notifications on this event
|
|
//
|
|
|
|
Status = gBS->RegisterProtocolNotify (
|
|
ProtocolGuid,
|
|
Event,
|
|
Registration
|
|
);
|
|
|
|
// ASSERT_EFI_ERROR (Status);
|
|
if (EFI_ERROR(Status)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// 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 the 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);
|
|
if (EFI_ERROR(Status)) {
|
|
return 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 the 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);
|
|
if (EFI_ERROR(Status)) {
|
|
return 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 is 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);
|
|
if (!Lock) {
|
|
return NULL;
|
|
}
|
|
|
|
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);
|
|
if (!Lock) {
|
|
return;
|
|
}
|
|
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);
|
|
if (!Lock) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
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);
|
|
if (!Lock) {
|
|
return;
|
|
}
|
|
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);
|
|
if (!ProtocolGuid) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
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 = NULL;
|
|
UINTN EntryCount = 0;
|
|
UINTN Index;
|
|
|
|
ASSERT (ProtocolGuid != NULL);
|
|
if (!ProtocolGuid) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// 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) {
|
|
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) {
|
|
FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
|
|
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) {
|
|
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) {
|
|
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) {
|
|
FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
|
|
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) {
|
|
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
|
|
//
|
|
FreePool (UnicodeStringTable[Index].Language);
|
|
|
|
//
|
|
// Free the Unicode String from the Unicode String Table
|
|
//
|
|
if (UnicodeStringTable[Index].UnicodeString != NULL) {
|
|
FreePool (UnicodeStringTable[Index].UnicodeString);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the Unicode String Table itself
|
|
//
|
|
FreePool (UnicodeStringTable);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
|
|
|
|
/**
|
|
[ATTENTION] This function will be deprecated for security reason.
|
|
|
|
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 The pointer to a Null-terminated Unicode string.
|
|
@param[in] Guid The 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);
|
|
if (!Name || !Guid) {
|
|
return 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;
|
|
}
|
|
|
|
/**
|
|
[ATTENTION] This function will be deprecated for security reason.
|
|
|
|
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 The 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);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
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);
|
|
if (!Name || !Guid || !Value) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
/** Return the attributes of the variable.
|
|
|
|
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(). The attributes are returned if
|
|
the caller provides a valid Attribute parameter.
|
|
|
|
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.
|
|
@param[out] Attr The pointer to the variable attributes as found in var store
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Allocate buffer failed.
|
|
@retval EFI_SUCCESS Find the specified variable.
|
|
@retval Others Errors Return errors from call to gRT->GetVariable.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
GetVariable3(
|
|
IN CONST CHAR16 *Name,
|
|
IN CONST EFI_GUID *Guid,
|
|
OUT VOID **Value,
|
|
OUT UINTN *Size OPTIONAL,
|
|
OUT UINT32 *Attr OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
|
|
ASSERT(Name != NULL && Guid != NULL && Value != NULL);
|
|
if (!Name || !Guid || !Value) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Try to get the variable size.
|
|
//
|
|
BufferSize = 0;
|
|
*Value = NULL;
|
|
if (Size != NULL) {
|
|
*Size = 0;
|
|
}
|
|
|
|
if (Attr != NULL) {
|
|
*Attr = 0;
|
|
}
|
|
|
|
Status = gRT->GetVariable((CHAR16 *)Name, (EFI_GUID *)Guid, Attr, &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, Attr, &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);
|
|
if (!SupportedLanguages) {
|
|
return 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;
|
|
}
|