X-Git-Url: https://code.delx.au/refind/blobdiff_plain/953397f78420efbd81d4ab60a2c01da0d2c19711..e0f6b77e5692ec112bb803202ae27f8c5d55de50:/refind/lib.c diff --git a/refind/lib.c b/refind/lib.c index be95e0c..03d90d5 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -46,8 +46,23 @@ #include "lib.h" #include "icns.h" #include "screen.h" -#include "refit_call_wrapper.h" -#include "RemovableMedia.h" +#include "../include/refit_call_wrapper.h" +#include "../include/RemovableMedia.h" + +#ifdef __MAKEWITH_GNUEFI +#define EfiReallocatePool ReallocatePool +#else +#define LibLocateHandle gBS->LocateHandleBuffer +#define DevicePathProtocol gEfiDevicePathProtocolGuid +#define BlockIoProtocol gEfiBlockIoProtocolGuid +#define LibFileSystemInfo EfiLibFileSystemInfo +#define LibOpenRoot EfiLibOpenRoot +EFI_DEVICE_PATH EndDevicePath[] = { + {END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}} +}; + +//#define EndDevicePath DevicePath +#endif // variables @@ -79,7 +94,7 @@ static VOID UninitVolumes(VOID); // // Converts forward slashes to backslashes, removes duplicate slashes, and -// removes slashes from both the start and end of the pathname. +// removes slashes from the end of the pathname. // Necessary because some (buggy?) EFI implementations produce "\/" strings // in pathnames, because some user inputs can produce duplicate directory // separators, and because we want consistent start and end slashes for @@ -91,20 +106,23 @@ VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName) { UINTN i, FinalChar = 0; BOOLEAN LastWasSlash = FALSE; - NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 2)); + NewName = AllocateZeroPool(sizeof(CHAR16) * (StrLen(PathName) + 4)); if (NewName != NULL) { for (i = 0; i < StrLen(PathName); i++) { if ((PathName[i] == L'/') || (PathName[i] == L'\\')) { - if ((!LastWasSlash) && (FinalChar != 0)) + if ((!LastWasSlash) /* && (FinalChar != 0) */) NewName[FinalChar++] = L'\\'; LastWasSlash = TRUE; } else { + if (FinalChar == 0) { + NewName[FinalChar++] = L'\\'; + } NewName[FinalChar++] = PathName[i]; LastWasSlash = FALSE; } // if/else } // for NewName[FinalChar] = 0; - if ((FinalChar > 0) && (NewName[FinalChar - 1] == L'\\')) + if ((FinalChar > 1) && (NewName[FinalChar - 1] == L'\\')) NewName[--FinalChar] = 0; if (FinalChar == 0) { NewName[0] = L'\\'; @@ -129,10 +147,9 @@ EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle) // find the current directory DevicePathAsString = DevicePathToStr(SelfLoadedImage->FilePath); CleanUpPathNameSlashes(DevicePathAsString); - if (SelfDirPath != NULL) - FreePool(SelfDirPath); + MyFreePool(SelfDirPath); SelfDirPath = FindPath(DevicePathAsString); - FreePool(DevicePathAsString); + MyFreePool(DevicePathAsString); return FinishInitRefitLib(); } @@ -224,7 +241,7 @@ VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID if (*ElementCount == 0) *ListPtr = AllocatePool(sizeof(VOID *) * AllocateCount); else - *ListPtr = ReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount); + *ListPtr = EfiReallocatePool(*ListPtr, sizeof(VOID *) * (*ElementCount), sizeof(VOID *) * AllocateCount); } (*ListPtr)[*ElementCount] = NewElement; (*ElementCount)++; @@ -234,14 +251,14 @@ VOID FreeList(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount) { UINTN i; - if (*ElementCount > 0) { + if ((*ElementCount > 0) && (**ListPtr != NULL)) { for (i = 0; i < *ElementCount; i++) { // TODO: call a user-provided routine for each element here - FreePool((*ListPtr)[i]); + MyFreePool((*ListPtr)[i]); } - FreePool(*ListPtr); + MyFreePool(*ListPtr); } -} +} // VOID FreeList() // // firmware device path discovery @@ -270,8 +287,7 @@ VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DE MaxPaths--; // leave space for the terminating NULL pointer // get all LoadedImage handles - Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, - &HandleCount, &Handles); + Status = LibLocateHandle(ByProtocol, &LoadedImageProtocol, NULL, &HandleCount, &Handles); if (CheckError(Status, L"while listing LoadedImage handles")) { if (HardcodedPathList) { for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) @@ -311,7 +327,7 @@ VOID ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DE PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath); } - FreePool(Handles); + MyFreePool(Handles); if (HardcodedPathList) { for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++) @@ -496,7 +512,7 @@ static VOID ScanVolumeDefaultIcon(IN OUT REFIT_VOLUME *Volume) } // switch() } -static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) +VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) { EFI_STATUS Status; EFI_DEVICE_PATH *DevicePath, *NextDevicePath; @@ -639,7 +655,7 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) if (FileExists(Volume->RootDir, VOLUME_ICON_NAME)) { Volume->VolIconImage = LoadIcns(Volume->RootDir, VOLUME_ICON_NAME, 128); } -} +} // ScanVolume() static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) { @@ -683,7 +699,8 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I Volume->DiskKind = WholeDiskVolume->DiskKind; Volume->IsMbrPartition = TRUE; Volume->MbrPartitionIndex = LogicalPartitionIndex++; - Volume->VolName = PoolPrint(L"Partition %d", Volume->MbrPartitionIndex + 1); + Volume->VolName = AllocateZeroPool(256 * sizeof(UINT16)); + SPrint(Volume->VolName, 255, L"Partition %d", Volume->MbrPartitionIndex + 1); Volume->BlockIO = WholeDiskVolume->BlockIO; Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA; Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO; @@ -715,15 +732,16 @@ VOID ScanVolumes(VOID) UINT8 *SectorBuffer1, *SectorBuffer2; UINTN SectorSum, i; - FreePool(Volumes); + MyFreePool(Volumes); Volumes = NULL; VolumesCount = 0; // get all filesystem handles Status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL, &HandleCount, &Handles); // was: &FileSystemProtocol - if (Status == EFI_NOT_FOUND) + if (Status == EFI_NOT_FOUND) { return; // no filesystems. strange, but true... + } if (CheckError(Status, L"while listing all file systems")) return; @@ -738,7 +756,7 @@ VOID ScanVolumes(VOID) if (Volume->DeviceHandle == SelfLoadedImage->DeviceHandle) SelfVolume = Volume; } - FreePool(Handles); + MyFreePool(Handles); if (SelfVolume == NULL) Print(L"WARNING: SelfVolume not found"); @@ -803,13 +821,15 @@ VOID ScanVolumes(VOID) // now we're reasonably sure the association is correct... Volume->IsMbrPartition = TRUE; Volume->MbrPartitionIndex = PartitionIndex; - if (Volume->VolName == NULL) - Volume->VolName = PoolPrint(L"Partition %d", PartitionIndex + 1); + if (Volume->VolName == NULL) { + Volume->VolName = AllocateZeroPool(sizeof(CHAR16) * 256); + SPrint(Volume->VolName, 255, L"Partition %d", PartitionIndex + 1); + } break; } - FreePool(SectorBuffer1); - FreePool(SectorBuffer2); + MyFreePool(SectorBuffer1); + MyFreePool(SectorBuffer2); } } @@ -906,8 +926,8 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, // free pointer from last call if (*DirEntry != NULL) { - FreePool(*DirEntry); - *DirEntry = NULL; + FreePool(*DirEntry); + *DirEntry = NULL; } // read next directory entry @@ -925,7 +945,7 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, Print(L"Reallocating buffer from %d to %d\n", LastBufferSize, BufferSize); #endif } - Buffer = ReallocatePool(Buffer, LastBufferSize, BufferSize); + Buffer = EfiReallocatePool(Buffer, LastBufferSize, BufferSize); LastBufferSize = BufferSize; } if (EFI_ERROR(Status)) { @@ -969,6 +989,60 @@ VOID DirIterOpen(IN EFI_FILE *BaseDir, IN CHAR16 *RelativePath OPTIONAL, OUT REF DirIter->LastFileInfo = NULL; } +#ifndef __MAKEWITH_GNUEFI +EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL; + +static EFI_STATUS +InitializeUnicodeCollationProtocol (VOID) +{ + EFI_STATUS Status; + + if (mUnicodeCollation != NULL) { + return EFI_SUCCESS; + } + + // + // BUGBUG: Proper impelmentation is to locate all Unicode Collation Protocol + // instances first and then select one which support English language. + // Current implementation just pick the first instance. + // + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollation2ProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + if (EFI_ERROR(Status)) { + Status = gBS->LocateProtocol ( + &gEfiUnicodeCollationProtocolGuid, + NULL, + (VOID **) &mUnicodeCollation + ); + + } + return Status; +} + +static BOOLEAN +MetaiMatch (IN CHAR16 *String, IN CHAR16 *Pattern) +{ + if (!mUnicodeCollation) { + InitializeUnicodeCollationProtocol(); + } + if (mUnicodeCollation) + return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern); + return FALSE; // Shouldn't happen +} + +static VOID StrLwr (IN OUT CHAR16 *Str) { + if (!mUnicodeCollation) { + InitializeUnicodeCollationProtocol(); + } + if (mUnicodeCollation) + mUnicodeCollation->StrLwr (mUnicodeCollation, Str); +} + +#endif + BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR16 *FilePattern OPTIONAL, OUT EFI_FILE_INFO **DirEntry) { @@ -977,8 +1051,8 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR CHAR16 *OnePattern; if (DirIter->LastFileInfo != NULL) { - FreePool(DirIter->LastFileInfo); - DirIter->LastFileInfo = NULL; + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; } if (EFI_ERROR(DirIter->LastStatus)) @@ -1009,13 +1083,13 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter) { - if (DirIter->LastFileInfo != NULL) { - FreePool(DirIter->LastFileInfo); - DirIter->LastFileInfo = NULL; - } - if (DirIter->CloseDirHandle) - refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle); - return DirIter->LastStatus; + if (DirIter->LastFileInfo != NULL) { + FreePool(DirIter->LastFileInfo); + DirIter->LastFileInfo = NULL; + } + if (DirIter->CloseDirHandle) + refit_call1_wrapper(DirIter->DirHandle->Close, DirIter->DirHandle); + return DirIter->LastStatus; } // @@ -1094,8 +1168,8 @@ BOOLEAN StriSubCmp(IN CHAR16 *SmallStr, IN CHAR16 *BigStr) { while ((!Found) && (StartPoint < NumCompares)) { Found = (StrnCmp(SmallCopy, &BigCopy[StartPoint++], SmallLen) == 0); } // while - FreePool(SmallCopy); - FreePool(BigCopy); + MyFreePool(SmallCopy); + MyFreePool(BigCopy); } // if return (Found); @@ -1130,7 +1204,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { } // if (*First != NULL) if (Second != NULL) StrCat(NewString, Second); - FreePool(*First); + MyFreePool(*First); *First = NewString; } else { Print(L"Error! Unable to allocate memory in MergeStrings()!\n"); @@ -1200,7 +1274,8 @@ CHAR16 *FindLastDirName(IN CHAR16 *Path) { // Returns the directory portion of a pathname. For instance, // if FullPath is 'EFI\foo\bar.efi', this function returns the -// string 'EFI\foo'. +// string 'EFI\foo'. The calling function is responsible for +// freeing the returned string's memory. CHAR16 *FindPath(IN CHAR16* FullPath) { UINTN i, LastBackslash = 0; CHAR16 *PathOnly; @@ -1214,6 +1289,62 @@ CHAR16 *FindPath(IN CHAR16* FullPath) { return (PathOnly); } +// Splits an EFI device path into device and filename components. For instance, if InString is +// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000)/\bzImage-3.5.1.efi, +// this function will truncate that input to +// PciRoot(0x0)/Pci(0x1f,0x2)/Ata(Secondary,Master,0x0)/HD(2,GPT,8314ae90-ada3-48e9-9c3b-09a88f80d921,0x96028,0xfa000) +// and return bzImage-3.5.1.efi as its return value. +// It does this by searching for the last ")" character in InString, copying everything +// after that string (after some cleanup) as the return value, and truncating the original +// input value. +// If InString contains no ")" character, this function leaves the original input string +// unmodified and returns a NULL value. +static CHAR16* SplitDeviceString(IN OUT CHAR16 *InString) { + INTN i; + CHAR16 *FileName = NULL; + BOOLEAN Found = FALSE; + + i = StrLen(InString) - 1; + while ((i >= 0) && (!Found)) { + if (InString[i] == L')') { + Found = TRUE; + FileName = StrDuplicate(&InString[i + 1]); + CleanUpPathNameSlashes(FileName); + InString[i + 1] = '\0'; + } // if + i--; + } // while + return FileName; +} // static CHAR16* SplitDeviceString() + +// Takes an input loadpath, splits it into disk and filename components, finds a matching +// DeviceVolume, and returns that and the filename (*loader). +VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader) { + CHAR16 *DeviceString, *VolumeDeviceString, *Temp; + UINTN i = 0; + BOOLEAN Found = FALSE; + + MyFreePool(*loader); + MyFreePool(*DeviceVolume); + *DeviceVolume = NULL; + DeviceString = DevicePathToStr(loadpath); + *loader = SplitDeviceString(DeviceString); + + while ((i < VolumesCount) && (!Found)) { + VolumeDeviceString = DevicePathToStr(Volumes[i]->DevicePath); + Temp = SplitDeviceString(VolumeDeviceString); + if (StriCmp(DeviceString, VolumeDeviceString) == 0) { + Found = TRUE; + *DeviceVolume = Volumes[i]; + } + MyFreePool(Temp); + MyFreePool(VolumeDeviceString); + i++; + } // while + + MyFreePool(DeviceString); +} // VOID FindVolumeAndFilename() + // Returns all the digits in the input string, including intervening // non-digit characters. For instance, if InString is "foo-3.3.4-7.img", // this function returns "3.3.4-7". If InString contains no digits, @@ -1278,6 +1409,29 @@ CHAR16 *FindCommaDelimited(IN CHAR16 *InString, IN UINTN Index) { return (FoundString); } // CHAR16 *FindCommaDelimited() +// Returns TRUE if SmallString is an element in the comma-delimited List, +// FALSE otherwise. Performs comparison case-insensitively (except on +// buggy EFIs with case-sensitive StriCmp() functions). +BOOLEAN IsIn(IN CHAR16 *SmallString, IN CHAR16 *List) { + UINTN i = 0; + BOOLEAN Found = FALSE; + CHAR16 *OneElement; + + if (SmallString && List) { + while (!Found && (OneElement = FindCommaDelimited(List, i++))) { + if (StriCmp(OneElement, SmallString) == 0) + Found = TRUE; + } // while + } // if + return Found; +} // BOOLEAN IsIn() + +// Implement FreePool the way it should have been done to begin with, so that +// it doesn't throw an ASSERT message if fed a NULL pointer.... +VOID MyFreePool(IN OUT VOID *Pointer) { + if (Pointer != NULL) + FreePool(Pointer); +} static EFI_GUID AppleRemovableMediaGuid = APPLE_REMOVABLE_MEDIA_PROTOCOL_GUID; @@ -1302,6 +1456,23 @@ BOOLEAN EjectMedia(VOID) { if (!EFI_ERROR(Status)) Ejected++; } - FreePool(Handles); + MyFreePool(Handles); return (Ejected > 0); } // VOID EjectMedia() + + +// Return the GUID as a string, suitable for display to the user. Note that the calling +// function is responsible for freeing the allocated memory. +CHAR16 * GuidAsString(EFI_GUID *GuidData) { + CHAR16 *TheString; + + TheString = AllocateZeroPool(42 * sizeof(CHAR16)); + if (TheString != 0) { + SPrint (TheString, 82, L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (UINTN)GuidData->Data1, (UINTN)GuidData->Data2, (UINTN)GuidData->Data3, + (UINTN)GuidData->Data4[0], (UINTN)GuidData->Data4[1], (UINTN)GuidData->Data4[2], + (UINTN)GuidData->Data4[3], (UINTN)GuidData->Data4[4], (UINTN)GuidData->Data4[5], + (UINTN)GuidData->Data4[6], (UINTN)GuidData->Data4[7]); + } + return TheString; +} // GuidAsString(EFI_GUID *GuidData)