From: srs5694 Date: Sun, 27 Apr 2014 00:21:34 +0000 (-0400) Subject: Added support for specifying volumes via partition GUID in manual boot X-Git-Url: https://code.delx.au/refind/commitdiff_plain/e3d2b4a15b8e4a6e7d6e3a6421270fccfb06c4f0 Added support for specifying volumes via partition GUID in manual boot stanzas. --- diff --git a/NEWS.txt b/NEWS.txt index c0f1dcb..a864e8e 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,10 @@ 0.7.10 (?/??/2014): ------------------- +- It's now possible to specify a volume by partition GUID number in a + manual boot stanza. This should be more reliable (albeit also more + awkward) than using a filesystem number (such as fs0: or fs1:). + - Fixed memory-allocation bug that could cause error message displays, and possibly hangs, when re-scanning boot loaders. diff --git a/mok/security_policy.c b/mok/security_policy.c index 2d0d0d1..33d3be7 100644 --- a/mok/security_policy.c +++ b/mok/security_policy.c @@ -24,9 +24,6 @@ struct _EFI_SECURITY_PROTOCOL; struct _EFI_DEVICE_PATH_PROTOCOL; typedef struct _EFI_SECURITY2_PROTOCOL EFI_SECURITY2_PROTOCOL; typedef struct _EFI_SECURITY_PROTOCOL EFI_SECURITY_PROTOCOL; -#ifdef __MAKEWITH_GNUEFI -typedef struct _EFI_DEVICE_PATH_PROTOCOL EFI_DEVICE_PATH_PROTOCOL; -#endif #if defined(EFIX64) #define MSABI __attribute__((ms_abi)) diff --git a/refind/config.c b/refind/config.c index 447638f..c1a7b5d 100644 --- a/refind/config.c +++ b/refind/config.c @@ -664,13 +664,18 @@ VOID ReadConfig(CHAR16 *FileName) // that volume. If not, leaves it unchanged. // Returns TRUE if a match was found, FALSE if not. static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { - UINTN i = 0, CountedVolumes = 0; + UINTN i = 0, CountedVolumes = 0, Length; INTN Number = -1; - BOOLEAN Found = FALSE; + BOOLEAN Found = FALSE, IdIsGuid = FALSE; + EFI_GUID VolGuid, NullGuid = NULL_GUID_VALUE; - if ((StrLen(Identifier) >= 2) && (Identifier[StrLen(Identifier) - 1] == L':') && + VolGuid = StringAsGuid(Identifier); + Length = StrLen(Identifier); + if ((Length >= 2) && (Identifier[Length - 1] == L':') && (Identifier[0] >= L'0') && (Identifier[0] <= L'9')) { Number = (INTN) Atoi(Identifier); + } else if (IsGuid(Identifier)) { + IdIsGuid = TRUE; } while ((i < VolumesCount) && (!Found)) { if (Number >= 0) { // User specified a volume by number @@ -681,11 +686,17 @@ static BOOLEAN FindVolume(REFIT_VOLUME **Volume, CHAR16 *Identifier) { } CountedVolumes++; } // if - } else { // User specified a volume by label + } else { // User specified a volume by label or GUID if (StriCmp(Identifier, Volumes[i]->VolName) == 0) { *Volume = Volumes[i]; Found = TRUE; } // if + if (IdIsGuid && !Found) { + if (GuidsAreEqual(&VolGuid, &(Volumes[i]->PartGuid)) && !GuidsAreEqual(&NullGuid, &(Volumes[i]->PartGuid))) { + *Volume = Volumes[i]; + Found = TRUE; + } // if + } // if } // if/else i++; } // while() diff --git a/refind/global.h b/refind/global.h index 586ff9b..5058d9d 100644 --- a/refind/global.h +++ b/refind/global.h @@ -148,6 +148,8 @@ // Files that may be Windows recovery files #define WINDOWS_RECOVERY_FILES L"EFI\\Microsoft\\Boot\\LrsBootmgr.efi" +#define NULL_GUID_VALUE { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} }; + // // global definitions // @@ -173,6 +175,7 @@ typedef struct { EFI_FILE *RootDir; CHAR16 *VolName; EFI_GUID VolUuid; + EFI_GUID PartGuid; UINTN VolNumber; EG_IMAGE *VolIconImage; EG_IMAGE *VolBadgeImage; diff --git a/refind/lib.c b/refind/lib.c index e45a226..0053c2b 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -764,6 +764,19 @@ static CHAR16 *GetVolumeName(IN REFIT_VOLUME *Volume) { return FoundName; } // static CHAR16 *GetVolumeName() +// Determine the unique GUID of the volume and store it. +static VOID SetPartGuid(REFIT_VOLUME *Volume, EFI_DEVICE_PATH_PROTOCOL *DevicePath) { + HARDDRIVE_DEVICE_PATH *HdDevicePath; + + if (Volume == NULL) + return; + + if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_HARDDRIVE_DP)) { + HdDevicePath = (HARDDRIVE_DEVICE_PATH*) DevicePath; + Volume->PartGuid = *((EFI_GUID*) HdDevicePath->Signature); + } +} // VOID SetPartGuid() + VOID ScanVolume(REFIT_VOLUME *Volume) { EFI_STATUS Status; @@ -805,6 +818,9 @@ VOID ScanVolume(REFIT_VOLUME *Volume) while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { NextDevicePath = NextDevicePathNode(DevicePath); + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH) { + SetPartGuid(Volume, DevicePath); + } if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || @@ -966,7 +982,7 @@ VOID ScanVolumes(VOID) UINTN SectorSum, i, VolNumber = 0; UINT8 *SectorBuffer1, *SectorBuffer2; EFI_GUID *UuidList; - EFI_GUID NullUuid = { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} }; + EFI_GUID NullUuid = NULL_GUID_VALUE; MyFreePool(Volumes); Volumes = NULL; @@ -1842,6 +1858,68 @@ BOOLEAN EjectMedia(VOID) { return (Ejected > 0); } // VOID EjectMedia() +// Converts consecutive characters in the input string into a +// number, interpreting the string as a hexadecimal number, starting +// at the specified position and continuing for the specified number +// of characters or until the end of the string, whichever is first. +// NumChars must be between 1 and 16. Ignores invalid characters. +UINT64 StrToHex(CHAR16 *Input, UINTN Pos, UINTN NumChars) { + UINT64 retval = 0x00; + UINTN NumDone = 0; + CHAR16 a; + + if ((Input == NULL) || (StrLen(Input) < Pos) || (NumChars == 0) || (NumChars > 16)) { + return 0; + } + + while ((StrLen(Input) >= Pos) && (NumDone < NumChars)) { + a = Input[Pos]; + if ((a >= '0') && (a <= '9')) { + retval *= 0x10; + retval += (a - '0'); + NumDone++; + } + if ((a >= 'a') && (a <= 'f')) { + retval *= 0x10; + retval += (a - 'a' + 0x0a); + NumDone++; + } + if ((a >= 'A') && (a <= 'F')) { + retval *= 0x10; + retval += (a - 'A' + 0x0a); + NumDone++; + } + Pos++; + } // while() + return retval; +} // StrToHex() + +// Returns TRUE if UnknownString can be interpreted as a GUID, FALSE otherwise. +// Note that the input string must have no extraneous spaces and must be +// conventionally formatted as a 36-character GUID, complete with dashes in +// appropriate places. +BOOLEAN IsGuid(CHAR16 *UnknownString) { + UINTN Length, i; + BOOLEAN retval = TRUE; + CHAR16 a; + + if (UnknownString == NULL) + return FALSE; + + Length = StrLen(UnknownString); + if (Length != 36) + return FALSE; + + for (i = 0; i < Length; i++) { + a = UnknownString[i]; + if (((i == 8) || (i == 13) || (i == 18) || (i == 23)) && (a != '-')) { + retval = FALSE; + } else if (((a < 'a') || (a > 'f')) && ((a < 'A') || (a > 'F')) && ((a < '0') && (a > '9'))) { + retval = FALSE; + } // if/else + } // for + return retval; +} // BOOLEAN IsGuid() // Return the GUID as a string, suitable for display to the user. Note that the calling // function is responsible for freeing the allocated memory. @@ -1858,3 +1936,34 @@ CHAR16 * GuidAsString(EFI_GUID *GuidData) { } return TheString; } // GuidAsString(EFI_GUID *GuidData) + +EFI_GUID StringAsGuid(CHAR16 * InString) { + EFI_GUID Guid = NULL_GUID_VALUE; + + if (!IsGuid(InString)) { + return Guid; + } + + Guid.Data1 = (UINT32) StrToHex(InString, 0, 8); + Guid.Data2 = (UINT16) StrToHex(InString, 9, 4); + Guid.Data3 = (UINT16) StrToHex(InString, 14, 4); + Guid.Data4[0] = (UINT8) StrToHex(InString, 19, 2); + Guid.Data4[1] = (UINT8) StrToHex(InString, 21, 2); + Guid.Data4[2] = (UINT8) StrToHex(InString, 23, 2); + Guid.Data4[3] = (UINT8) StrToHex(InString, 26, 2); + Guid.Data4[4] = (UINT8) StrToHex(InString, 28, 2); + Guid.Data4[5] = (UINT8) StrToHex(InString, 30, 2); + Guid.Data4[6] = (UINT8) StrToHex(InString, 32, 2); + Guid.Data4[7] = (UINT8) StrToHex(InString, 34, 2); + + return Guid; +} // EFI_GUID StringAsGuid() + +// Returns TRUE if the two GUIDs are equal, FALSE otherwise +BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2) { + return ((Guid1->Data1 == Guid2->Data1) && (Guid1->Data2 == Guid2->Data2) && (Guid1->Data3 == Guid2->Data3) && + (Guid1->Data4[0] == Guid2->Data4[0]) && (Guid1->Data4[1] == Guid2->Data4[1]) && + (Guid1->Data4[2] == Guid2->Data4[2]) && (Guid1->Data4[3] == Guid2->Data4[3]) && + (Guid1->Data4[4] == Guid2->Data4[4]) && (Guid1->Data4[5] == Guid2->Data4[5]) && + (Guid1->Data4[6] == Guid2->Data4[6]) && (Guid1->Data4[7] == Guid2->Data4[7])); +} // BOOLEAN CompareGuids() \ No newline at end of file diff --git a/refind/lib.h b/refind/lib.h index b0f555d..bc3454c 100644 --- a/refind/lib.h +++ b/refind/lib.h @@ -48,6 +48,35 @@ #ifdef __MAKEWITH_GNUEFI #include "efi.h" #include "efilib.h" +#pragma pack(1) + +/** + This protocol can be used on any device handle to obtain generic path/location + information concerning the physical device or logical device. If the handle does + not logically map to a physical device, the handle may not necessarily support + the device path protocol. The device path describes the location of the device + the handle is for. The size of the Device Path can be determined from the structures + that make up the Device Path. +**/ +typedef struct { + UINT8 Type; ///< 0x01 Hardware Device Path. + ///< 0x02 ACPI Device Path. + ///< 0x03 Messaging Device Path. + ///< 0x04 Media Device Path. + ///< 0x05 BIOS Boot Specification Device Path. + ///< 0x7F End of Hardware Device Path. + + UINT8 SubType; ///< Varies by Type + ///< 0xFF End Entire Device Path, or + ///< 0x01 End This Instance of a Device Path and start a new + ///< Device Path. + + UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define + ///< type of data. Size of data is included in Length. + +} EFI_DEVICE_PATH_PROTOCOL; + +#pragma pack() #else #include "../include/tiano_includes.h" #endif @@ -123,6 +152,10 @@ VOID MyFreePool(IN OUT VOID *Pointer); BOOLEAN EjectMedia(VOID); +UINT64 StrToHex(CHAR16 *Input, UINTN Position, UINTN NumChars); +BOOLEAN IsGuid(CHAR16 *UnknownString); CHAR16 * GuidAsString(EFI_GUID *GuidData); +EFI_GUID StringAsGuid(CHAR16 * InString); +BOOLEAN GuidsAreEqual(EFI_GUID *Guid1, EFI_GUID *Guid2); #endif \ No newline at end of file diff --git a/refind/main.c b/refind/main.c index ae35fa3..25c7a5a 100644 --- a/refind/main.c +++ b/refind/main.c @@ -159,7 +159,7 @@ static VOID AboutrEFInd(VOID) { if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.1"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.2"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith");