2013-01-31 01:25:25 +04:00
|
|
|
/*++
|
|
|
|
|
|
|
|
Copyright (c) 1998 Intel Corporation
|
|
|
|
|
|
|
|
Module Name:
|
|
|
|
|
|
|
|
misc.c
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Revision History
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "lib.h"
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
AllocatePool (
|
|
|
|
IN UINTN Size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
VOID *p;
|
|
|
|
|
|
|
|
Status = uefi_call_wrapper(BS->AllocatePool, 3, PoolAllocationType, Size, &p);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
DEBUG((D_ERROR, "AllocatePool: out of pool %x\n", Status));
|
|
|
|
p = NULL;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
AllocateZeroPool (
|
|
|
|
IN UINTN Size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
VOID *p;
|
|
|
|
|
|
|
|
p = AllocatePool (Size);
|
|
|
|
if (p) {
|
|
|
|
ZeroMem (p, Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID *
|
2024-04-24 19:12:04 +03:00
|
|
|
EFIAPI
|
|
|
|
ReallocatePool_1 (
|
|
|
|
IN UINTN OldSize,
|
|
|
|
IN UINTN NewSize,
|
|
|
|
IN VOID *OldPool OPTIONAL
|
|
|
|
)
|
2013-01-31 01:25:25 +04:00
|
|
|
{
|
|
|
|
VOID *NewPool;
|
|
|
|
|
|
|
|
NewPool = NULL;
|
|
|
|
if (NewSize) {
|
|
|
|
NewPool = AllocatePool (NewSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OldPool) {
|
|
|
|
if (NewPool) {
|
|
|
|
CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
FreePool (OldPool);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewPool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FreePool (
|
|
|
|
IN VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
|
|
|
uefi_call_wrapper(BS->FreePool, 1, Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ZeroMem (
|
|
|
|
IN VOID *Buffer,
|
|
|
|
IN UINTN Size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RtZeroMem (Buffer, Size);
|
|
|
|
}
|
|
|
|
|
2021-08-04 19:52:13 +03:00
|
|
|
VOID EFIAPI
|
2013-01-31 01:25:25 +04:00
|
|
|
SetMem (
|
|
|
|
IN VOID *Buffer,
|
|
|
|
IN UINTN Size,
|
|
|
|
IN UINT8 Value
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RtSetMem (Buffer, Size, Value);
|
|
|
|
}
|
|
|
|
|
2021-08-04 19:52:13 +03:00
|
|
|
VOID EFIAPI
|
2024-05-04 18:13:42 +03:00
|
|
|
CopyMem_1 (
|
2013-01-31 01:25:25 +04:00
|
|
|
IN VOID *Dest,
|
2021-08-04 19:52:13 +03:00
|
|
|
IN VOID *Src,
|
2013-01-31 01:25:25 +04:00
|
|
|
IN UINTN len
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RtCopyMem (Dest, Src, len);
|
|
|
|
}
|
|
|
|
|
2024-05-02 17:52:11 +03:00
|
|
|
VOID EFIAPI
|
|
|
|
CopyMemC (
|
|
|
|
IN VOID *Dest,
|
|
|
|
IN CONST VOID *Src,
|
|
|
|
IN UINTN len
|
|
|
|
)
|
|
|
|
{
|
|
|
|
RtCopyMemC (Dest, Src, len);
|
|
|
|
}
|
|
|
|
|
2013-01-31 01:25:25 +04:00
|
|
|
INTN
|
|
|
|
CompareMem (
|
2013-10-03 01:19:55 +04:00
|
|
|
IN CONST VOID *Dest,
|
|
|
|
IN CONST VOID *Src,
|
2013-01-31 01:25:25 +04:00
|
|
|
IN UINTN len
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return RtCompareMem (Dest, Src, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
GrowBuffer(
|
|
|
|
IN OUT EFI_STATUS *Status,
|
|
|
|
IN OUT VOID **Buffer,
|
|
|
|
IN UINTN BufferSize
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Helper function called as part of the code needed
|
|
|
|
to allocate the proper sized buffer for various
|
|
|
|
EFI interfaces.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Status - Current status
|
|
|
|
|
|
|
|
Buffer - Current allocated buffer, or NULL
|
|
|
|
|
|
|
|
BufferSize - Current buffer size needed
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
TRUE - if the buffer was reallocated and the caller
|
|
|
|
should try the API again.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BOOLEAN TryAgain;
|
|
|
|
|
|
|
|
//
|
|
|
|
// If this is an initial request, buffer will be null with a new buffer size
|
|
|
|
//
|
|
|
|
|
|
|
|
if (!*Buffer && BufferSize) {
|
|
|
|
*Status = EFI_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If the status code is "buffer too small", resize the buffer
|
|
|
|
//
|
|
|
|
|
|
|
|
TryAgain = FALSE;
|
|
|
|
if (*Status == EFI_BUFFER_TOO_SMALL) {
|
|
|
|
|
|
|
|
if (*Buffer) {
|
|
|
|
FreePool (*Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
*Buffer = AllocatePool (BufferSize);
|
|
|
|
|
|
|
|
if (*Buffer) {
|
|
|
|
TryAgain = TRUE;
|
|
|
|
} else {
|
|
|
|
*Status = EFI_OUT_OF_RESOURCES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// If there's an error, free the buffer
|
|
|
|
//
|
|
|
|
|
|
|
|
if (!TryAgain && EFI_ERROR(*Status) && *Buffer) {
|
|
|
|
FreePool (*Buffer);
|
|
|
|
*Buffer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TryAgain;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EFI_MEMORY_DESCRIPTOR *
|
|
|
|
LibMemoryMap (
|
|
|
|
OUT UINTN *NoEntries,
|
|
|
|
OUT UINTN *MapKey,
|
|
|
|
OUT UINTN *DescriptorSize,
|
|
|
|
OUT UINT32 *DescriptorVersion
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
EFI_MEMORY_DESCRIPTOR *Buffer;
|
|
|
|
UINTN BufferSize;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize for GrowBuffer loop
|
|
|
|
//
|
|
|
|
|
2014-02-13 23:05:10 +04:00
|
|
|
Status = EFI_SUCCESS;
|
2013-01-31 01:25:25 +04:00
|
|
|
Buffer = NULL;
|
|
|
|
BufferSize = sizeof(EFI_MEMORY_DESCRIPTOR);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Call the real function
|
|
|
|
//
|
|
|
|
|
|
|
|
while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
|
|
|
|
Status = uefi_call_wrapper(BS->GetMemoryMap, 5, &BufferSize, Buffer, MapKey, DescriptorSize, DescriptorVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Convert buffer size to NoEntries
|
|
|
|
//
|
|
|
|
|
|
|
|
if (!EFI_ERROR(Status)) {
|
|
|
|
*NoEntries = BufferSize / *DescriptorSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
LibGetVariableAndSize (
|
|
|
|
IN CHAR16 *Name,
|
|
|
|
IN EFI_GUID *VendorGuid,
|
|
|
|
OUT UINTN *VarSize
|
|
|
|
)
|
|
|
|
{
|
2021-03-19 19:14:48 +03:00
|
|
|
EFI_STATUS Status = EFI_SUCCESS;
|
2013-01-31 01:25:25 +04:00
|
|
|
VOID *Buffer;
|
|
|
|
UINTN BufferSize;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize for GrowBuffer loop
|
|
|
|
//
|
|
|
|
|
|
|
|
Buffer = NULL;
|
|
|
|
BufferSize = 100;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Call the real function
|
|
|
|
//
|
|
|
|
|
|
|
|
while (GrowBuffer (&Status, &Buffer, BufferSize)) {
|
|
|
|
Status = uefi_call_wrapper(
|
|
|
|
RT->GetVariable,
|
|
|
|
5,
|
|
|
|
Name,
|
|
|
|
VendorGuid,
|
|
|
|
NULL,
|
|
|
|
&BufferSize,
|
|
|
|
Buffer
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (Buffer) {
|
|
|
|
*VarSize = BufferSize;
|
|
|
|
} else {
|
|
|
|
*VarSize = 0;
|
|
|
|
}
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID *
|
|
|
|
LibGetVariable (
|
|
|
|
IN CHAR16 *Name,
|
|
|
|
IN EFI_GUID *VendorGuid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINTN VarSize;
|
|
|
|
|
|
|
|
return LibGetVariableAndSize (Name, VendorGuid, &VarSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
LibDeleteVariable (
|
|
|
|
IN CHAR16 *VarName,
|
|
|
|
IN EFI_GUID *VarGuid
|
|
|
|
)
|
|
|
|
{
|
|
|
|
VOID *VarBuf;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
VarBuf = LibGetVariable(VarName,VarGuid);
|
|
|
|
|
|
|
|
Status = EFI_NOT_FOUND;
|
|
|
|
|
|
|
|
if (VarBuf) {
|
|
|
|
//
|
|
|
|
// Delete variable from Storage
|
|
|
|
//
|
|
|
|
Status = uefi_call_wrapper(
|
|
|
|
RT->SetVariable,
|
|
|
|
5,
|
|
|
|
VarName, VarGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
|
|
0, NULL
|
|
|
|
);
|
|
|
|
ASSERT (!EFI_ERROR(Status));
|
|
|
|
FreePool(VarBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
2013-10-11 19:12:28 +04:00
|
|
|
EFI_STATUS
|
|
|
|
LibSetNVVariable (
|
|
|
|
IN CHAR16 *VarName,
|
|
|
|
IN EFI_GUID *VarGuid,
|
|
|
|
IN UINTN DataSize,
|
|
|
|
IN VOID *Data
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = uefi_call_wrapper(
|
|
|
|
RT->SetVariable,
|
|
|
|
5,
|
|
|
|
VarName, VarGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
|
|
DataSize, Data
|
|
|
|
);
|
|
|
|
ASSERT (!EFI_ERROR(Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
LibSetVariable (
|
|
|
|
IN CHAR16 *VarName,
|
|
|
|
IN EFI_GUID *VarGuid,
|
|
|
|
IN UINTN DataSize,
|
|
|
|
IN VOID *Data
|
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = uefi_call_wrapper(
|
|
|
|
RT->SetVariable,
|
|
|
|
5,
|
|
|
|
VarName, VarGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
|
|
DataSize, Data
|
|
|
|
);
|
|
|
|
ASSERT (!EFI_ERROR(Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
2013-01-31 01:25:25 +04:00
|
|
|
EFI_STATUS
|
|
|
|
LibInsertToTailOfBootOrder (
|
|
|
|
IN UINT16 BootOption,
|
|
|
|
IN BOOLEAN OnlyInsertIfEmpty
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT16 *BootOptionArray;
|
|
|
|
UINT16 *NewBootOptionArray;
|
|
|
|
UINTN VarSize;
|
|
|
|
UINTN Index;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
BootOptionArray = LibGetVariableAndSize (VarBootOrder, &EfiGlobalVariable, &VarSize);
|
|
|
|
if (VarSize != 0 && OnlyInsertIfEmpty) {
|
|
|
|
if (BootOptionArray) {
|
|
|
|
FreePool (BootOptionArray);
|
|
|
|
}
|
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
VarSize += sizeof(UINT16);
|
|
|
|
NewBootOptionArray = AllocatePool (VarSize);
|
2021-06-22 01:03:18 +03:00
|
|
|
if (!NewBootOptionArray)
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
|
2013-01-31 01:25:25 +04:00
|
|
|
for (Index = 0; Index < ((VarSize/sizeof(UINT16)) - 1); Index++) {
|
|
|
|
NewBootOptionArray[Index] = BootOptionArray[Index];
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Insert in the tail of the array
|
|
|
|
//
|
|
|
|
NewBootOptionArray[Index] = BootOption;
|
|
|
|
|
|
|
|
Status = uefi_call_wrapper(
|
|
|
|
RT->SetVariable,
|
|
|
|
5,
|
|
|
|
VarBootOrder, &EfiGlobalVariable,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
|
|
VarSize, (VOID*) NewBootOptionArray
|
|
|
|
);
|
|
|
|
|
2021-06-22 01:03:18 +03:00
|
|
|
FreePool (NewBootOptionArray);
|
2013-01-31 01:25:25 +04:00
|
|
|
if (BootOptionArray) {
|
|
|
|
FreePool (BootOptionArray);
|
|
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
ValidMBR(
|
|
|
|
IN MASTER_BOOT_RECORD *Mbr,
|
|
|
|
IN EFI_BLOCK_IO *BlkIo
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UINT32 StartingLBA, EndingLBA;
|
|
|
|
UINT32 NewEndingLBA;
|
|
|
|
INTN i, j;
|
|
|
|
BOOLEAN ValidMbr;
|
|
|
|
|
|
|
|
if (Mbr->Signature != MBR_SIGNATURE) {
|
|
|
|
//
|
|
|
|
// The BPB also has this signature, so it can not be used alone.
|
|
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ValidMbr = FALSE;
|
|
|
|
for (i=0; i<MAX_MBR_PARTITIONS; i++) {
|
|
|
|
if ( Mbr->Partition[i].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) == 0 ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ValidMbr = TRUE;
|
|
|
|
StartingLBA = EXTRACT_UINT32(Mbr->Partition[i].StartingLBA);
|
|
|
|
EndingLBA = StartingLBA + EXTRACT_UINT32(Mbr->Partition[i].SizeInLBA) - 1;
|
|
|
|
if (EndingLBA > BlkIo->Media->LastBlock) {
|
|
|
|
//
|
|
|
|
// Compatability Errata:
|
|
|
|
// Some systems try to hide drive space with thier INT 13h driver
|
|
|
|
// This does not hide space from the OS driver. This means the MBR
|
|
|
|
// that gets created from DOS is smaller than the MBR created from
|
|
|
|
// a real OS (NT & Win98). This leads to BlkIo->LastBlock being
|
|
|
|
// wrong on some systems FDISKed by the OS.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
if (BlkIo->Media->LastBlock < MIN_MBR_DEVICE_SIZE) {
|
|
|
|
//
|
|
|
|
// If this is a very small device then trust the BlkIo->LastBlock
|
|
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EndingLBA > (BlkIo->Media->LastBlock + MBR_ERRATA_PAD)) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
for (j=i+1; j<MAX_MBR_PARTITIONS; j++) {
|
|
|
|
if (Mbr->Partition[j].OSIndicator == 0x00 || EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) >= StartingLBA &&
|
|
|
|
EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) <= EndingLBA ) {
|
|
|
|
//
|
|
|
|
// The Start of this region overlaps with the i'th region
|
|
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
NewEndingLBA = EXTRACT_UINT32(Mbr->Partition[j].StartingLBA) + EXTRACT_UINT32(Mbr->Partition[j].SizeInLBA) - 1;
|
|
|
|
if ( NewEndingLBA >= StartingLBA && NewEndingLBA <= EndingLBA ) {
|
|
|
|
//
|
|
|
|
// The End of this region overlaps with the i'th region
|
|
|
|
//
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Non of the regions overlapped so MBR is O.K.
|
|
|
|
//
|
|
|
|
return ValidMbr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT8
|
|
|
|
DecimaltoBCD(
|
|
|
|
IN UINT8 DecValue
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return RtDecimaltoBCD (DecValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UINT8
|
|
|
|
BCDtoDecimal(
|
|
|
|
IN UINT8 BcdValue
|
|
|
|
)
|
|
|
|
{
|
|
|
|
return RtBCDtoDecimal (BcdValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
LibGetSystemConfigurationTable(
|
|
|
|
IN EFI_GUID *TableGuid,
|
|
|
|
IN OUT VOID **Table
|
|
|
|
)
|
|
|
|
|
|
|
|
{
|
|
|
|
UINTN Index;
|
|
|
|
|
|
|
|
for(Index=0;Index<ST->NumberOfTableEntries;Index++) {
|
|
|
|
if (CompareGuid(TableGuid,&(ST->ConfigurationTable[Index].VendorGuid))==0) {
|
|
|
|
*Table = ST->ConfigurationTable[Index].VendorTable;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CHAR16 *
|
|
|
|
LibGetUiString (
|
|
|
|
IN EFI_HANDLE Handle,
|
|
|
|
IN UI_STRING_TYPE StringType,
|
|
|
|
IN ISO_639_2 *LangCode,
|
|
|
|
IN BOOLEAN ReturnDevicePathStrOnMismatch
|
|
|
|
)
|
|
|
|
{
|
|
|
|
UI_INTERFACE *Ui;
|
|
|
|
UI_STRING_TYPE Index;
|
|
|
|
UI_STRING_ENTRY *Array;
|
|
|
|
EFI_STATUS Status;
|
|
|
|
|
|
|
|
Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &UiProtocol, (VOID *)&Ui);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Skip the first strings
|
|
|
|
//
|
|
|
|
for (Index = UiDeviceString, Array = Ui->Entry; Index < StringType; Index++, Array++) {
|
|
|
|
while (Array->LangCode) {
|
|
|
|
Array++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Search for the match
|
|
|
|
//
|
|
|
|
while (Array->LangCode) {
|
|
|
|
if (strcmpa (Array->LangCode, LangCode) == 0) {
|
|
|
|
return Array->UiString;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (ReturnDevicePathStrOnMismatch) ? DevicePathToStr(DevicePathFromHandle(Handle)) : NULL;
|
|
|
|
}
|