From: srs5694 Date: Sat, 3 May 2014 18:43:42 +0000 (-0400) Subject: Limit length of firmware description string in Info screen, to avoid X-Git-Url: https://code.delx.au/refind/commitdiff_plain/224ffad523048df8ad5f14038de21b7afe6a3b6a Limit length of firmware description string in Info screen, to avoid causing the whole page to be blank on 800x600 displays. --- diff --git a/NEWS.txt b/NEWS.txt index eb424b0..1f1024d 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,11 @@ 0.7.10 (?/??/2014): ------------------- +- rEFInd now limits the length of the firmware name string shown in the + system information screen to 65 characters. This is done because at least + one EFI presents a longer string by default, and this causes the entire + information display to come up empty on 800x600 displays. + - rEFInd now uses the partition's name (as stored in the GPT data structures) as a fallback for the filesystem's name if the latter can't be found. Exceptions are if the partition name is one of three generic diff --git a/docs/refind/configfile.html b/docs/refind/configfile.html index 47e1661..aa0bc96 100644 --- a/docs/refind/configfile.html +++ b/docs/refind/configfile.html @@ -320,7 +320,7 @@ timeout 20 dont_scan_volumes or don't_scan_volumes - filesystem label(s) + filesystem or partition label(s) Adds the specified volume or volumes to a volume "blacklist"—these filesystems are not scanned for EFI boot loaders. This may be useful to keep unwanted EFI boot entries, such as for a Macintosh recovery partition, from appearing on the main list of boot loaders. The default value is "Recovery HD", LRS_ESP, to keep the Mac OS X and Lenovo Windows recovery volumes from appearing. (These should get their own tools icon instead—see the showtools token.) Note that on a Macintosh with whole-disk encryption, you may need to uncomment this token and leave "Recovery HD" off the list to boot the system. @@ -406,8 +406,8 @@ default_selection elilo volume - filesystem label - Sets the volume that's used for subsequent file accesses (by icon and loader, and by implication by initrd if loader follows volume). You pass this token a filesystem's label or a volume number. A filesystem label is typically displayed under the volume's icon in file managers and that rEFInd displays on its menu at the end of the boot prompt string. If this label isn't unique, the first volume with the specified label is used. The matching is nominally case-insensitive, but on some EFIs it's case-sensitive. If a filesystem has no label, you can use a volume number followed by a colon, such as 0: to refer to the first filesystem or 1: to refer to the second. The assignment of numbers is arbitrary and may not be consistent across boots, though. It might change if you insert an optical disc or plug in a USB flash drive, for instance. If this option is not set, the volume defaults to the one from which rEFInd launched. + filesystem label, partition label, GUID value, or filesystem number + Sets the volume that's used for subsequent file accesses (by icon and loader, and by implication by initrd if loader follows volume). You pass this token a filesystem's label, a partition's label, a partition's GUID, or a volume number. A filesystem or partition label is typically displayed under the volume's icon in file managers and rEFInd displays it on its menu at the end of the boot prompt string. If this label isn't unique, the first volume with the specified label is used. The matching is nominally case-insensitive, but on some EFIs it's case-sensitive. If a filesystem has no label, you can use a partition GUID number. You can also use a volume number followed by a colon, such as 0: to refer to the first filesystem or 1: to refer to the second. The assignment of numbers is arbitrary and may not be consistent across boots, though. It might change if you insert an optical disc or plug in a USB flash drive, for instance. If this option is not set, the volume defaults to the one from which rEFInd launched. loader @@ -476,9 +476,9 @@ menuentry "Windows via shell script" {

This example sets up three entries: one for Ubuntu Linux, one for Gentoo Linux, and one to launch a shell script. Note that the first two entries use different directory separators, simply to demonstrate the fact that it's possible. The Ubuntu entry sets no icon, since rEFInd will note that the boot loader is stored in the ubuntu directory, and it will automatically find the appropriate Ubuntu icon (os_ubuntu.icns). This option is, however, disabled, so no matching icon will appear when you reboot unless you first comment out or delete the disabled line.

- + -

The Gentoo entry begins with an icon specification to be sure that the icon is loaded from the same volume as rEFInd. (If the icon were stored on the same filesystem as the kernel, you'd place the icon line after the volume line.) This entry uses the volume token to tell rEFInd to load the kernel and initial RAM disk file from the filesystem called G_KERNELS. It passes the filename for an initial RAM disk using the initrd line and free-form options using the options line. Note that the kernel filename does not include a .efi extension, which keeps rEFInd from picking up the kernel file in its auto-scans.

+

The Gentoo entry begins with an icon specification to be sure that the icon is loaded from the same volume as rEFInd. (If the icon were stored on the same filesystem as the kernel, you'd place the icon line after the volume line.) This entry uses the volume token to tell rEFInd to load the kernel and initial RAM disk file from the filesystem or partition called G_KERNELS. It passes the filename for an initial RAM disk using the initrd line and free-form options using the options line. Note that the kernel filename does not include a .efi extension, which keeps rEFInd from picking up the kernel file in its auto-scans.

The Windows via shell script entry may seem puzzling, but its purpose is to launch an OS (Windows in this case) after performing additional pre-boot initialization, which is handled by an EFI shell script. This works because you can pass the name of a shell script to an EFI shell—the script is named on the stanza's options line, using EFI file notation. The shell script, in turn, does whatever it needs to do and then launches the OS's boot loader:

diff --git a/docs/refind/features.html b/docs/refind/features.html index fb2fc79..fc47944 100644 --- a/docs/refind/features.html +++ b/docs/refind/features.html @@ -15,7 +15,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.com

Originally written: 3/14/2012; last Web page update: -4/20/2014, referencing rEFInd 0.7.9

+4/20/2014, referencing rEFInd 0.7.10

This Web page is provided free of charge and with no annoying outside ads; however, I did take time to prepare it, and Web hosting does cost money. If you find this Web page useful, please consider making a small donation to help keep this site up and running. Thanks!

@@ -183,6 +183,8 @@ lack a usable CSM.
  • Improved flexibility in setting the default OS to boot. rEFInd enables specifying the default by any substring in the description. You can also specify multiple defaults, so that if the first isn't available, another will take its place (which is useful when using removable disks). You can also add time specifications to set a default to be used only during certain hours of the day.
  • +
  • Support for partition names or GUID values as fallbacks for filesystem labels in certain configuration file settings. Partition names may be shown as values to be displayed as part of the descriptive text for boot tags on the main menu, too, if a filesystem has no label.
  • +
  • The ability to fine-tune options passed to EFI boot loaders, via manual configuration.
  • An option editor to enable you to edit the options passed to an EFI boot loader on a per-boot basis.
  • diff --git a/refind/gpt.c b/refind/gpt.c index eb106b7..83dd6d3 100644 --- a/refind/gpt.c +++ b/refind/gpt.c @@ -60,19 +60,25 @@ VOID ClearGptData(GPT_DATA *Data) { // TODO: Make this work on big-endian systems; at the moment, it contains // little-endian assumptions! -// Returns TRUE if the GPT header data appear valid, FALSE otherwise. +// Returns TRUE if the GPT protective MBR and header data appear valid, +// FALSE otherwise. static BOOLEAN GptHeaderValid(GPT_DATA *GptData) { BOOLEAN IsValid; UINT32 CrcValue, StoredCrcValue; UINTN HeaderSize = sizeof(GPT_HEADER); - IsValid = ((GptData != NULL) && (GptData->ProtectiveMBR != NULL) && (GptData->Header != NULL)); - IsValid = IsValid && (GptData->ProtectiveMBR->MBRSignature == 0xAA55); + if ((GptData == NULL) || (GptData->ProtectiveMBR == NULL) || (GptData->Header == NULL)) + return FALSE; + + IsValid = (GptData->ProtectiveMBR->MBRSignature == 0xAA55); IsValid = IsValid && ((GptData->ProtectiveMBR->partitions[0].type == 0xEE) || (GptData->ProtectiveMBR->partitions[1].type == 0xEE) || (GptData->ProtectiveMBR->partitions[2].type == 0xEE) || (GptData->ProtectiveMBR->partitions[3].type == 0xEE)); - IsValid = IsValid && (GptData->Header->signature == 0x5452415020494645ULL); + + IsValid = IsValid && ((GptData->Header->signature == 0x5452415020494645ULL) && + (GptData->Header->spec_revision == 0x00010000) && + (GptData->Header->entry_size == 128)); // Looks good so far; check CRC value.... if (IsValid) { @@ -89,29 +95,32 @@ static BOOLEAN GptHeaderValid(GPT_DATA *GptData) { return IsValid; } // BOOLEAN GptHeaderValid() -// Read GPT data from Volume and store it in Data. Note that this function +// Read GPT data from Volume and store it in *Data. Note that this function // may be called on a Volume that is not in fact a GPT disk (an MBR disk, // a partition, etc.), in which case it will return EFI_LOAD_ERROR or some // other error condition. In this case, *Data will be left alone. // Note also that this function checks CRCs and does other sanity checks // on the input data, but does NOT resort to using the backup data if the -// primary data structures are damaged. +// primary data structures are damaged. The intent is that the function +// be very conservative about reading GPT data. Currently (version 0.7.10), +// rEFInd uses the data only to provide access to partition names. This is +// non-critical data, so it's OK to return nothing, but having the program +// hang on reading garbage or return nonsense could be very bad. EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) { EFI_STATUS Status = EFI_SUCCESS; UINT64 BufferSize; - UINT32 TableCrc; UINTN i; GPT_DATA *GptData; // Temporary holding storage; transferred to *Data later if ((Volume == NULL) || (Data == NULL)) - Status = EFI_INVALID_PARAMETER; + return EFI_INVALID_PARAMETER; // get block i/o if ((Status == EFI_SUCCESS) && (Volume->BlockIO == NULL)) { Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); if (EFI_ERROR(Status)) { Volume->BlockIO = NULL; - Print(L"Warning: Can't get BlockIO protocol.\n"); + Print(L"Warning: Can't get BlockIO protocol in ReadGptData().\n"); Status = EFI_NOT_READY; } } // if @@ -129,7 +138,7 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) { // Read the MBR and store it in GptData->ProtectiveMBR. if (Status == EFI_SUCCESS) { Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, - 0, 512, (VOID*) GptData->ProtectiveMBR); + 0, sizeof(MBR_RECORD), (VOID*) GptData->ProtectiveMBR); } // Read the GPT header and store it in GptData->Header. @@ -138,29 +147,22 @@ EFI_STATUS ReadGptData(REFIT_VOLUME *Volume, GPT_DATA **Data) { 1, sizeof(GPT_HEADER), GptData->Header); } - // If it looks like a valid protective MBR, try to do more with it.... + // If it looks like a valid protective MBR & GPT header, try to do more with it.... if (Status == EFI_SUCCESS) { if (GptHeaderValid(GptData)) { // Load actual GPT table.... BufferSize = GptData->Header->entry_count * 128; - if (GptData->Entries != NULL) - MyFreePool(GptData->Entries); GptData->Entries = AllocatePool(BufferSize); - if (GptData->Entries == NULL) { + if (GptData->Entries == NULL) Status = EFI_OUT_OF_RESOURCES; - } // if - if (Status == EFI_SUCCESS) { + if (Status == EFI_SUCCESS) Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, GptData->Header->entry_lba, BufferSize, GptData->Entries); - } // if // Check CRC status of table - if (Status == EFI_SUCCESS) { - TableCrc = crc32(0x0, GptData->Entries, BufferSize); - if (TableCrc != GptData->Header->entry_crc32) - Status = EFI_CRC_ERROR; - } // if + if ((Status == EFI_SUCCESS) && (crc32(0x0, GptData->Entries, BufferSize) != GptData->Header->entry_crc32)) + Status = EFI_CRC_ERROR; // Now, ensure that every name is null-terminated.... if (Status == EFI_SUCCESS) { @@ -243,7 +245,5 @@ VOID AddPartitionTable(REFIT_VOLUME *Volume) { ClearGptData(GptData); NumTables = 0; } // if/else - Print(L"In AddPartitionTable(), total number of tables is %d\n", NumTables); - PauseForKey(); } // VOID AddPartitionTable() diff --git a/refind/lib.c b/refind/lib.c index dc1c1b3..0c4089f 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -1582,6 +1582,89 @@ CHAR16 *FindPath(IN CHAR16* FullPath) { return (PathOnly); } +/*++ + * + * Routine Description: + * + * Find a substring. + * + * Arguments: + * + * String - Null-terminated string to search. + * StrCharSet - Null-terminated string to search for. + * + * Returns: + * The address of the first occurrence of the matching substring if successful, or NULL otherwise. + * --*/ +CHAR16* MyStrStr (CHAR16 *String, CHAR16 *StrCharSet) +{ + CHAR16 *Src; + CHAR16 *Sub; + + if ((String == NULL) || (StrCharSet == NULL)) + return NULL; + + Src = String; + Sub = StrCharSet; + + while ((*String != L'\0') && (*StrCharSet != L'\0')) { + if (*String++ != *StrCharSet) { + String = ++Src; + StrCharSet = Sub; + } else { + StrCharSet++; + } + } + if (*StrCharSet == L'\0') { + return Src; + } else { + return NULL; + } +} // CHAR16 *MyStrStr() + +// Restrict TheString to at most Limit characters. +// Does this in two ways: +// - Locates stretches of two or more spaces and compresses +// them down to one space. +// - Truncates TheString +// Returns TRUE if changes were made, FALSE otherwise +BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit) { + CHAR16 *SubString, *TempString; + UINTN i; + BOOLEAN HasChanged = FALSE; + + // SubString will be NULL or point WITHIN TheString + SubString = MyStrStr(TheString, L" "); + while (SubString != NULL) { + i = 0; + while (SubString[i] == L' ') + i++; + if (i >= StrLen(SubString)) { + SubString[0] = '\0'; + HasChanged = TRUE; + } else { + TempString = StrDuplicate(&SubString[i]); + if (TempString != NULL) { + StrCpy(&SubString[1], TempString); + MyFreePool(TempString); + HasChanged = TRUE; + } else { + // memory allocation problem; abort to avoid potentially infinite loop! + break; + } // if/else + } // if/else + SubString = MyStrStr(TheString, L" "); + } // while + + // If the string is still too long, truncate it.... + if (StrLen(TheString) > Limit) { + TheString[Limit] = '\0'; + HasChanged = TRUE; + } // if + + return HasChanged; +} // BOOLEAN LimitStringLength() + // 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) { diff --git a/refind/lib.h b/refind/lib.h index 8a71249..be26dc7 100644 --- a/refind/lib.h +++ b/refind/lib.h @@ -114,6 +114,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar); CHAR16 *FindExtension(IN CHAR16 *Path); CHAR16 *FindLastDirName(IN CHAR16 *Path); CHAR16 *FindPath(IN CHAR16* FullPath); +BOOLEAN LimitStringLength(CHAR16 *TheString, UINTN Limit); VOID FindVolumeAndFilename(IN EFI_DEVICE_PATH *loadpath, OUT REFIT_VOLUME **DeviceVolume, OUT CHAR16 **loader); BOOLEAN SplitVolumeAndFilename(IN OUT CHAR16 **Path, OUT CHAR16 **VolName); CHAR16 *FindNumbers(IN CHAR16 *InString); diff --git a/refind/main.c b/refind/main.c index 64fe898..dcbb1fd 100644 --- a/refind/main.c +++ b/refind/main.c @@ -160,9 +160,11 @@ struct LOADER_LIST { static VOID AboutrEFInd(VOID) { + CHAR16 *FirmwareVendor; + if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.4"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.7.9.5"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith"); @@ -179,7 +181,9 @@ static VOID AboutrEFInd(VOID) #else AddMenuInfoLine(&AboutMenu, L" Platform: unknown"); #endif - AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, + FirmwareVendor = StrDuplicate(ST->FirmwareVendor); + LimitStringLength(FirmwareVendor, 65); // More than ~65 causes empty info page on 800x600 display + AddMenuInfoLine(&AboutMenu, PoolPrint(L" Firmware: %s %d.%02d", FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & ((1 << 16) - 1))); AddMenuInfoLine(&AboutMenu, PoolPrint(L" Screen Output: %s", egScreenDescription())); AddMenuInfoLine(&AboutMenu, L""); @@ -1094,7 +1098,7 @@ static BOOLEAN ShouldScan(REFIT_VOLUME *Volume, CHAR16 *Path) { UINTN i = 0; BOOLEAN ScanIt = TRUE; - if (IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) + if ((IsIn(Volume->VolName, GlobalConfig.DontScanVolumes)) || (IsIn(Volume->PartName, GlobalConfig.DontScanVolumes))) return FALSE; if ((StriCmp(Path, SelfDirPath) == 0) && (Volume->DeviceHandle == SelfVolume->DeviceHandle))