Sync/gnu-efi/lib/misc.c
Curle d588e232c4 Major overhaul of this branch.
This branch has been dedicated to purely the UEFI bootloader.
As such, all other code has been removed.

This code can be compiled with Visual Studio, gcc or llvm.
2019-07-17 21:10:29 +01:00

564 lines
12 KiB
C

/*++
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 *
ReallocatePool (
IN VOID *OldPool,
IN UINTN OldSize,
IN UINTN NewSize
)
{
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);
}
VOID
SetMem (
IN VOID *Buffer,
IN UINTN Size,
IN UINT8 Value
)
{
RtSetMem (Buffer, Size, Value);
}
VOID
CopyMem (
IN VOID *Dest,
IN CONST VOID *Src,
IN UINTN len
)
{
RtCopyMem (Dest, Src, len);
}
INTN
CompareMem (
IN CONST VOID *Dest,
IN CONST VOID *Src,
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
//
Status = EFI_SUCCESS;
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
)
{
EFI_STATUS Status;
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);
}
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);
}
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);
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
);
if (NewBootOptionArray) {
FreePool (NewBootOptionArray);
}
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;
}