From 1f5e6865fb9bf8ebb78b4818a6d54440c7c4004a Mon Sep 17 00:00:00 2001
From: srs5694 by Roderick W. Smith, rodsmith@rodsbooks.com Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4 Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5 I'm a technical writer and consultant specializing in Linux technologies. 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! by Roderick W. Smith, rodsmith@rodsbooks.com Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4 Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5 I'm a technical writer and consultant specializing in Linux technologies. 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!
Another way to hide a boot loader is to move it into rEFInd's own directory. In order to keep rEFInd from showing up in its own menu, it ignores boot loaders in its own directory. This obviously includes the rEFInd binary file itself, but also anything else you might store there.
-In addition to hiding boot loaders, you can adjust their icons. You can do this in either of two ways:
+In addition to hiding boot loaders, you can adjust their icons. You can do this in any of three ways for auto-detected boot loaders:
rEFInd assigns icons to the Windows and OS X boot loaders based on their conventional locations, so they get suitable icons even though they don't follow these rules.
+As a special case, rEFInd assigns icons to the Windows and OS X boot loaders based on their conventional locations, so they get suitable icons even though they don't follow these rules.
+ +In addition to the main OS tag icon, you can set the badge icon for a volume by creating a file called .VolumeBadge.icns in the root directory of a partition. This icon file must include a 32x32 bitmap. If present, it replaces the disk-type icons that are overlaid on the main OS icon. If you use this feature, the badge is applied to all the boot loaders read from the disk, not just those stored in the root directory or the Apple boot loader location. You could use this feature to set a custom badge for different specific disks or to help differentiate multiple OS X installations on one computer.
by Roderick W. Smith, by Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
- +Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -101,7 +100,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.comby Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -96,7 +96,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.comIf you download a zip file, you'll need to extract the files with a tool such as unzip, which is included with Linux and Mac OS X. Numerous Windows utilities also support this format, such as PKZIP and 7-Zip.
+You should be able to create a bootable USB flash drive from either the binary zip file or the CD-R image file; just treat the flash drive as if it were a hard disk and install rEFInd as described on the installation page. Using the fallback boot loader name of EFI/boot/bootx64.efi is likely to be the most useful way to install rEFInd to a removable medium.
+If you use Arch Linux, you can obtain rEFInd from its repositories, in both stable and git (experimental) releases. The git release is likely to include pre-release bug fixes and new features, but those features may be poorly tested or undocumented.
+You can also obtain rEFInd from the Nix Packages collection, which creates packages for a number of OSes using its own packaging system.
+To the best of my knowledge, no other Linux distribution yet includes rEFInd in its repositories. That's likely to change in time. If you hear of rEFInd being included in an OS's official package set, feel free to drop me a line.
by Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
diff --git a/docs/refind/installing.html b/docs/refind/installing.html index fef11b8..978a70e 100644 --- a/docs/refind/installing.html +++ b/docs/refind/installing.html @@ -14,7 +14,7 @@by Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -260,14 +260,6 @@ Filesystem 1K-blocks Used Available Use% Mounted on protective MBR. You can obtain the file from the original rEFIt package.I've seen links to other versions of these tools from time to time on the Web, so if you try one of these programs and it crashes or behaves strangely, try performing a Web search; you may turn up something that works better for you than the one to which I've linked.
diff --git a/docs/refind/linux.html b/docs/refind/linux.html index 3508243..939e798 100644 --- a/docs/refind/linux.html +++ b/docs/refind/linux.html @@ -9,12 +9,12 @@ -by Roderick W. Smith, by Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/19/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/19/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -105,13 +105,25 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.comThe Linux EFI stub loader is a way to turn a Linux kernel into an EFI application. In a sense, the kernel becomes its own boot loader. This approach to booting Linux is very elegant in some ways, but as described on the page to which I just linked, it has its disadvantages, too. One challenge to booting in this way is that modern Linux installations typically require that the kernel be passed a number of options at boot time. These tell the kernel where the Linux root (/) filesystem is, where the initial RAM disk is, and so on. Without these options, Linux won't boot. These options are impossible for a generic boot loader to guess without a little help. It's possible to build a kernel with a default set of options, but this is rather limiting. Thus, rEFInd provides configuration options to help.
-With all versions of rEFInd, you can create manual boot loader stanzas in the refind.conf file to identify a Linux kernel and to pass it all the options it needs. This approach is effective and flexible, but it requires editing a single configuration file. If a computer boots two different Linux distributions, and if both were to support rEFInd, problems might arise as each one tries to modify its own rEFInd configuration; or the one that controls rEFInd might set inappropriate options for another distribution. This is a problem that's been a minor annoyance for years under BIOS, since the same potential for poor configuration applies to LILO, GRUB Legacy, and GRUB 2 on BIOS. The most reliable solution there is to chainload one boot loader to another. The same solution is possible under EFI, but rEFInd offers another possibility.
+With all versions of rEFInd, you can create manual boot loader stanzas +in the refind.conf file to identify a Linux kernel and to pass it +all the options it needs. This approach is effective and flexible, but it +requires editing a single configuration file for all the OSes you want to +define in this way. If a computer boots two different Linux distributions, +and if both were to support rEFInd, problems might arise as each one tries +to modify its own rEFInd configuration; or the one that controls rEFInd +might set inappropriate options for another distribution. This is a problem +that's been a minor annoyance for years under BIOS, since the same +potential for poor configuration applies to LILO, GRUB Legacy, and GRUB 2 +on BIOS. The most reliable solution there is to chainload one boot loader +to another. The same solution is possible under EFI, but rEFInd offers +another possibility.
rEFInd 0.2.1 and later supports semi-automatic Linux EFI stub loader detection. This feature works as part of the standard boot loader scan operation, but it extends it as follows:
On the whole, this method of configuration has a lot going for it. For distribution maintainers, if you place your Linux kernel files (with EFI stub support) on the ESP, with suitable filenames, matching initial RAM disk files, and a refind_linux.conf file, then any rEFInd 0.2.3 or later installation should detect your files, even if the user installs another distribution with another rEFInd that takes over from yours. (If the user, or this other rEFInd installation, disables auto-detection, this won't work.)
For end users, this method is simpler than maintaining manual configurations in refind.conf (or equivalents for ELILO or GRUB). To install a new kernel, you need only copy it and its initial RAM disk, under suitable names, to a scanned directory on the ESP. There's no need to touch any configuration file, provided you've already set up refind_linux.conf in your kernel's directory. You will, however, have to adjust refind_linux.conf if you make certain changes, such as if your root directory identifier changes.
diff --git a/docs/refind/revisions.html b/docs/refind/revisions.html index 2cb3326..bb06648 100644 --- a/docs/refind/revisions.html +++ b/docs/refind/revisions.html @@ -9,12 +9,12 @@ -by Roderick W. Smith, by Roderick W. Smith, rodsmith@rodsbooks.com
-Last Web page update: 4/5/2012
+Last Web page update: 4/9/2012
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -93,6 +93,8 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.comby Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
@@ -89,7 +89,7 @@ href="mailto:rodsmith@rodsbooks.com">rodsmith@rodsbooks.comrEFInd is far from perfect. It's based on rEFIt, which has an list of active bugs on its project page on Sourceforge. I have not studied this bug list in detail for rEFInd's first release, although I've probably fixed a few of those bugs because I encountered them myself. Other bugs I may never fix because I lack the necessary hardware for testing.
+rEFInd is far from perfect. It's based on rEFIt, which has a list of active bugs on its project page on Sourceforge. I have not studied this bug list in detail for rEFInd's first release, although I've probably fixed a few of those bugs because I encountered them myself. Other bugs I may never fix because I lack the necessary hardware for testing.
This page exists to document some of rEFInd's known bugs and limitations, as well as features I hope to add in the future. Some of the items on this list are things that you may be able to help with, so if you'd like to contribute, feel free to drop me a line!
@@ -117,6 +117,8 @@ program. I'm not sure what you'd use in Windows to create ICNS files.by Roderick W. Smith, rodsmith@rodsbooks.com
-Originally written: 3/14/2012; last Web page update: 4/5/2012, referencing rEFInd 0.2.4
+Originally written: 3/14/2012; last Web page update: 4/9/2012, referencing rEFInd 0.2.5
I'm a technical writer and consultant specializing in Linux technologies. 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!
diff --git a/libeg/image.c b/libeg/image.c index 5907c09..13bb758 100644 --- a/libeg/image.c +++ b/libeg/image.c @@ -77,11 +77,11 @@ EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAl EG_IMAGE * egCopyImage(IN EG_IMAGE *Image) { EG_IMAGE *NewImage; - + NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha); if (NewImage == NULL) return NULL; - + CopyMem(NewImage->PixelData, Image->PixelData, Image->Width * Image->Height * sizeof(EG_PIXEL)); return NewImage; } @@ -221,7 +221,7 @@ static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, } else if ((StriCmp(Format, L"ICNS") == 0) || (StriCmp(Format, L"icns") == 0)) { NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha); } // if/else - + return NewImage; } @@ -231,19 +231,19 @@ EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN Wan UINT8 *FileData; UINTN FileDataLength; EG_IMAGE *NewImage; - + if (BaseDir == NULL || FileName == NULL) return NULL; - + // load file Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength); if (EFI_ERROR(Status)) return NULL; - + // decode it NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FileName), 128, WantAlpha); FreePool(FileData); - + return NewImage; } @@ -253,24 +253,24 @@ EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN UINTN IconSi UINT8 *FileData; UINTN FileDataLength; EG_IMAGE *NewImage; - + if (BaseDir == NULL || FileName == NULL) return NULL; - + // load file Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength); if (EFI_ERROR(Status)) { // Print(L"In egLoadIcon(), Status = %d after egLoadFile(); aborting load!\n", Status); return NULL; } - + // decode it NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FileName), IconSize, TRUE); // Print(L"Done with egDecodeAny(), used extension '%s'\n", egFindExtension(FileName)); // if (NewImage == NULL) // Print(L"Returning NULL from egLoadIcon()\n"); FreePool(FileData); - + return NewImage; } diff --git a/libeg/load_icns.c b/libeg/load_icns.c index 6af234d..5477f46 100644 --- a/libeg/load_icns.c +++ b/libeg/load_icns.c @@ -108,14 +108,14 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic // not an icns file... return NULL; } - + FetchPixelSize = IconSize; for (;;) { DataPtr = NULL; DataLen = 0; MaskPtr = NULL; MaskLen = 0; - + Ptr = FileData + 8; BufferEnd = FileData + FileDataLength; // iterate over tagged blocks in the file @@ -123,7 +123,7 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7]; if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file break; - + // extract the appropriate blocks for each pixel size if (FetchPixelSize == 128) { if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') { @@ -135,7 +135,7 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } - + } else if (FetchPixelSize == 48) { if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; @@ -144,7 +144,7 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } - + } else if (FetchPixelSize == 32) { if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; @@ -153,7 +153,7 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } - + } else if (FetchPixelSize == 16) { if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') { DataPtr = Ptr + 8; @@ -162,12 +162,12 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic MaskPtr = Ptr + 8; MaskLen = BlockLen - 8; } - + } - + Ptr += BlockLen; } - + /* FUTURE: try to load a different size and scale it later if (DataPtr == NULL && FetchPixelSize == 32) { FetchPixelSize = 128; @@ -176,18 +176,18 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic */ break; } - + if (DataPtr == NULL) return NULL; // no image found - + // allocate image structure and buffer NewImage = egCreateImage(FetchPixelSize, FetchPixelSize, WantAlpha); if (NewImage == NULL) return NULL; PixelCount = FetchPixelSize * FetchPixelSize; - + if (DataLen < PixelCount * 3) { - + // pixel data is compressed, RGB planar CompData = DataPtr; CompLen = DataLen; @@ -198,9 +198,9 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic if (CompLen > 0) { Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen); } - + } else { - + // pixel data is uncompressed, RGB interleaved SrcPtr = DataPtr; DestPtr = NewImage->PixelData; @@ -209,17 +209,17 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic DestPtr->g = *SrcPtr++; DestPtr->b = *SrcPtr++; } - + } - + // add/set alpha plane if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha) egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount); else egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); - + // FUTURE: scale to originally requested size if we had to load another size - + return NewImage; } diff --git a/mkcdimage b/mkcdimage index ff58829..b8824f1 100755 --- a/mkcdimage +++ b/mkcdimage @@ -74,6 +74,10 @@ mkisofs -A "Bootable rEFInd" -V "rEFInd $Version" -volset "rEFInd $Version" \ # Create a bootable USB flash drive image, using the FAT filesystem # created above and a stored partition table image (plus some empty # sectors).... +# +# Note: Seems to work on only a few systems, so I'm not distributing +# the resulting images yet.... +# rm ../../refind-flashdrive-$Version.* cat $StartDir/flashparts.img refind-bin-$Version.img > refind-flashdrive-$Version.img cp $StartDir/README-flashdrive.txt ./ @@ -92,7 +96,7 @@ mv refind-flashdrive-$Version/refind-flashdrive-$Version.img ../ cd ../ # Zip up the optical disc image.... -rm refind-cd-$Version.zip +rm -f refind-cd-$Version.zip zip -9 refind-cd-$Version.zip refind-cd-$Version.iso -#rm -r temp/ +rm -r temp/ diff --git a/refind/config.c b/refind/config.c index 955948b..e7ceb17 100644 --- a/refind/config.c +++ b/refind/config.c @@ -109,7 +109,7 @@ static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_F File->End8Ptr = File->Current8Ptr + File->BufferSize; File->Current16Ptr = (CHAR16 *)File->Buffer; File->End16Ptr = File->Current16Ptr + (File->BufferSize >> 1); - + // detect encoding File->Encoding = ENCODING_ISO8859_1; // default: 1:1 translation of CHAR8 to CHAR16 if (File->BufferSize >= 4) { @@ -126,7 +126,7 @@ static EFI_STATUS ReadFile(IN EFI_FILE_HANDLE BaseDir, CHAR16 *FileName, REFIT_F } // TODO: detect other encodings as they are implemented } - + return EFI_SUCCESS; } @@ -252,10 +252,10 @@ UINTN ReadTokenLine(IN REFIT_FILE *File, OUT CHAR16 ***TokenList) if (*p == 0 || *p == '#') LineFinished = TRUE; *p++ = 0; - + AddListElement((VOID ***)TokenList, &TokenCount, (VOID *)StrDuplicate(Token)); } - + FreePool(Line); } return (TokenCount); @@ -322,7 +322,7 @@ VOID ReadConfig(VOID) TokenCount = ReadTokenLine(&File, &TokenList); if (TokenCount == 0) break; - + if (StriCmp(TokenList[0], L"timeout") == 0) { HandleInt(TokenList, TokenCount, &(GlobalConfig.Timeout)); diff --git a/refind/global.h b/refind/global.h index 1218c44..63bc008 100644 --- a/refind/global.h +++ b/refind/global.h @@ -91,6 +91,7 @@ typedef struct { EFI_HANDLE DeviceHandle; EFI_FILE *RootDir; CHAR16 *VolName; + EG_IMAGE *VolIconImage; EG_IMAGE *VolBadgeImage; UINTN DiskKind; BOOLEAN IsAppleLegacy; diff --git a/refind/lib.c b/refind/lib.c index f5278ae..3c61782 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -63,6 +63,10 @@ UINTN VolumesCount = 0; // Maximum size for disk sectors #define SECTOR_SIZE 4096 +// Default names for volume badges (mini-icon to define disk type) and icons +#define VOLUME_BADGE_NAME L".VolumeBadge.icns" +#define VOLUME_ICON_NAME L".VolumeIcon.icns" + // functions static EFI_STATUS FinishInitRefitLib(VOID); @@ -435,7 +439,7 @@ static VOID ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT BOOLEAN *Bootabl CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16); } } - + } else { #if REFIT_DEBUG > 0 CheckError(Status, L"while reading boot sector"); @@ -468,7 +472,7 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) UINTN PartialLength; EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr; BOOLEAN Bootable; - + // get device path Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle)); #if REFIT_DEBUG > 0 @@ -479,9 +483,9 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) #endif } #endif - + Volume->DiskKind = DISK_KIND_INTERNAL; // default - + // get block i/o Status = refit_call3_wrapper(BS->HandleProtocol, Volume->DeviceHandle, &BlockIoProtocol, (VOID **) &(Volume->BlockIO)); if (EFI_ERROR(Status)) { @@ -491,16 +495,16 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) if (Volume->BlockIO->Media->BlockSize == 2048) Volume->DiskKind = DISK_KIND_OPTICAL; } - + // scan for bootcode and MBR table Bootable = FALSE; ScanVolumeBootcode(Volume, &Bootable); - + // detect device type DevicePath = Volume->DevicePath; while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) { NextDevicePath = NextDevicePathNode(DevicePath); - + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH && (DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP || @@ -512,44 +516,44 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) Volume->DiskKind = DISK_KIND_OPTICAL; // El Torito entry -> optical disk Bootable = TRUE; } - + if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) { Volume->IsAppleLegacy = TRUE; // legacy BIOS device entry // TODO: also check for Boot Camp GUID Bootable = FALSE; // this handle's BlockIO is just an alias for the whole device } - + if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH) { // make a device path for the whole device PartialLength = (UINT8 *)NextDevicePath - (UINT8 *)(Volume->DevicePath); DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH)); CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength); CopyMem((UINT8 *)DiskDevicePath + PartialLength, EndDevicePath, sizeof(EFI_DEVICE_PATH)); - + // get the handle for that path RemainingDevicePath = DiskDevicePath; //Print(L" * looking at %s\n", DevicePathToStr(RemainingDevicePath)); Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &WholeDiskHandle); //Print(L" * remaining: %s\n", DevicePathToStr(RemainingDevicePath)); FreePool(DiskDevicePath); - + if (!EFI_ERROR(Status)) { //Print(L" - original handle: %08x - disk handle: %08x\n", (UINT32)DeviceHandle, (UINT32)WholeDiskHandle); - + // get the device path for later Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &DevicePathProtocol, (VOID **) &DiskDevicePath); if (!EFI_ERROR(Status)) { Volume->WholeDiskDevicePath = DuplicateDevicePath(DiskDevicePath); } - + // look at the BlockIO protocol Status = refit_call3_wrapper(BS->HandleProtocol, WholeDiskHandle, &BlockIoProtocol, (VOID **) &Volume->WholeDiskBlockIO); if (!EFI_ERROR(Status)) { - + // check the media block size if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048) Volume->DiskKind = DISK_KIND_OPTICAL; - + } else { Volume->WholeDiskBlockIO = NULL; //CheckError(Status, L"from HandleProtocol"); @@ -557,10 +561,10 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) } //else // CheckError(Status, L"from LocateDevicePath"); } - + DevicePath = NextDevicePath; } // while - + if (!Bootable) { #if REFIT_DEBUG > 0 if (Volume->HasBootCode) @@ -568,16 +572,16 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) #endif Volume->HasBootCode = FALSE; } - + // default volume icon based on disk kind ScanVolumeDefaultIcon(Volume); - + // open the root directory of the volume Volume->RootDir = LibOpenRoot(Volume->DeviceHandle); if (Volume->RootDir == NULL) { return; } - + // get volume name FileSystemInfoPtr = LibFileSystemInfo(Volume->RootDir); if (FileSystemInfoPtr != NULL) { @@ -591,8 +595,11 @@ static VOID ScanVolume(IN OUT REFIT_VOLUME *Volume) // - name derived from file system type or partition type // get custom volume icon if present - if (FileExists(Volume->RootDir, L".VolumeIcon.icns")) - Volume->VolBadgeImage = LoadIcns(Volume->RootDir, L".VolumeIcon.icns", 32); + if (FileExists(Volume->RootDir, VOLUME_BADGE_NAME)) + Volume->VolBadgeImage = LoadIcns(Volume->RootDir, VOLUME_BADGE_NAME, 32); + if (FileExists(Volume->RootDir, VOLUME_ICON_NAME)) { + Volume->VolIconImage = LoadIcns(Volume->RootDir, VOLUME_ICON_NAME, 128); + } } static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry) @@ -605,9 +612,9 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I UINT8 SectorBuffer[512]; BOOLEAN Bootable; MBR_PARTITION_INFO *EMbrTable; - + ExtBase = MbrEntry->StartLBA; - + for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) { // read current EMBR Status = refit_call5_wrapper(WholeDiskVolume->BlockIO->ReadBlocks, @@ -619,7 +626,7 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55) break; EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446); - + // scan logical partitions in this EMBR NextExtCurrent = 0; for (i = 0; i < 4; i++) { @@ -631,7 +638,7 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I NextExtCurrent = ExtBase + EMbrTable[i].StartLBA; break; } else { - + // found a logical partition Volume = AllocateZeroPool(sizeof(REFIT_VOLUME)); Volume->DiskKind = WholeDiskVolume->DiskKind; @@ -641,16 +648,16 @@ static VOID ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_I Volume->BlockIO = WholeDiskVolume->BlockIO; Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA; Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO; - + Bootable = FALSE; ScanVolumeBootcode(Volume, &Bootable); if (!Bootable) Volume->HasBootCode = FALSE; - + ScanVolumeDefaultIcon(Volume); - + AddListElement((VOID ***) &Volumes, &VolumesCount, Volume); - + } } } @@ -696,7 +703,7 @@ VOID ScanVolumes(VOID) if (SelfVolume == NULL) Print(L"WARNING: SelfVolume not found"); - + // second pass: relate partitions and whole disk devices for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; @@ -732,7 +739,7 @@ VOID ScanVolumes(VOID) // check size if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1) continue; - + // compare boot sector read through offset vs. directly Status = refit_call5_wrapper(Volume->BlockIO->ReadBlocks, Volume->BlockIO, Volume->BlockIO->Media->MediaId, @@ -751,9 +758,9 @@ VOID ScanVolumes(VOID) SectorSum += SectorBuffer1[i]; if (SectorSum < 1000) continue; - + // TODO: mark entry as non-bootable if it is an extended partition - + // now we're reasonably sure the association is correct... Volume->IsMbrPartition = TRUE; Volume->MbrPartitionIndex = PartitionIndex; @@ -761,11 +768,11 @@ VOID ScanVolumes(VOID) Volume->VolName = PoolPrint(L"Partition %d", PartitionIndex + 1); break; } - + FreePool(SectorBuffer1); FreePool(SectorBuffer2); } - + } } /* VOID ScanVolumes() */ @@ -773,15 +780,15 @@ static VOID UninitVolumes(VOID) { REFIT_VOLUME *Volume; UINTN VolumeIndex; - + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; - + if (Volume->RootDir != NULL) { refit_call1_wrapper(Volume->RootDir->Close, Volume->RootDir); Volume->RootDir = NULL; } - + Volume->DeviceHandle = NULL; Volume->BlockIO = NULL; Volume->WholeDiskBlockIO = NULL; @@ -795,15 +802,15 @@ VOID ReinitVolumes(VOID) UINTN VolumeIndex; EFI_DEVICE_PATH *RemainingDevicePath; EFI_HANDLE DeviceHandle, WholeDiskHandle; - + for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) { Volume = Volumes[VolumeIndex]; - + if (Volume->DevicePath != NULL) { // get the handle for that path RemainingDevicePath = Volume->DevicePath; Status = refit_call3_wrapper(BS->LocateDevicePath, &BlockIoProtocol, &RemainingDevicePath, &DeviceHandle); - + if (!EFI_ERROR(Status)) { Volume->DeviceHandle = DeviceHandle; @@ -855,15 +862,15 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, VOID *Buffer; UINTN LastBufferSize, BufferSize; INTN IterCount; - + for (;;) { - + // free pointer from last call if (*DirEntry != NULL) { FreePool(*DirEntry); *DirEntry = NULL; } - + // read next directory entry LastBufferSize = BufferSize = 256; Buffer = AllocatePool(BufferSize); @@ -886,16 +893,16 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, FreePool(Buffer); break; } - + // check for end of listing if (BufferSize == 0) { // end of directory listing FreePool(Buffer); break; } - + // entry is ready to be returned *DirEntry = (EFI_FILE_INFO *)Buffer; - + // filter results if (FilterMode == 1) { // only return directories if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY)) @@ -905,7 +912,7 @@ EFI_STATUS DirNextEntry(IN EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, break; } else // no filter or unknown filter -> return everything break; - + } return Status; } @@ -930,10 +937,10 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR FreePool(DirIter->LastFileInfo); DirIter->LastFileInfo = NULL; } - + if (EFI_ERROR(DirIter->LastStatus)) return FALSE; // stop iteration - + for (;;) { DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode); if (EFI_ERROR(DirIter->LastStatus)) @@ -949,7 +956,7 @@ BOOLEAN DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CHAR } else break; } - + *DirEntry = DirIter->LastFileInfo; return TRUE; } @@ -1066,7 +1073,7 @@ VOID MergeStrings(IN OUT CHAR16 **First, IN CHAR16 *Second, CHAR16 AddChar) { if (Second != NULL) Length2 = StrLen(Second); NewString = AllocatePool(sizeof(CHAR16) * (Length1 + Length2 + 2)); - NewString[0] = 0; + NewString[0] = L'\0'; if (NewString != NULL) { if (*First != NULL) { StrCat(NewString, *First); diff --git a/refind/main.c b/refind/main.c index ea16053..6959a05 100644 --- a/refind/main.c +++ b/refind/main.c @@ -83,7 +83,7 @@ static VOID AboutrEFInd(VOID) { if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.4.2"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.2.5"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); @@ -175,7 +175,7 @@ static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths, if (ErrorInStep != NULL) *ErrorInStep = 3; } - + // re-open file handles ReinitRefitLib(); @@ -234,15 +234,16 @@ static CHAR16 * FindInitrd(IN CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { KernelVersion = FindNumbers(FileName); Path = FindPath(LoaderPath); + MergeStrings(&Path, L"\\", 0); // Add trailing backslash; necessary for root directory DirIterOpen(Volume->RootDir, Path, &DirIter); while ((DirIterNext(&DirIter, 2, L"init*", &DirEntry)) && (InitrdName == NULL)) { InitrdVersion = FindNumbers(DirEntry->FileName); if (KernelVersion != NULL) { if (StriCmp(InitrdVersion, KernelVersion) == 0) - InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } else { if (InitrdVersion == NULL) - InitrdName = PoolPrint(L"%s\\%s", Path, DirEntry->FileName); + InitrdName = PoolPrint(L"%s%s", Path, DirEntry->FileName); } // if/else if (InitrdVersion != NULL) FreePool(InitrdVersion); @@ -521,17 +522,20 @@ static CHAR16 * GetMainLinuxOptions(IN CHAR16 * LoaderPath, IN REFIT_VOLUME *Vol // that will (with luck) work fairly automatically. VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME *Volume) { CHAR16 IconFileName[256]; - CHAR16 *FileName, *OSIconName = NULL, *Temp; + CHAR16 *FileName, *PathOnly, *OSIconName = NULL, *Temp; CHAR16 ShortcutLetter = 0; FileName = Basename(LoaderPath); + PathOnly = FindPath(LoaderPath); // locate a custom icon for the loader StrCpy(IconFileName, LoaderPath); ReplaceExtension(IconFileName, L".icns"); if (FileExists(Volume->RootDir, IconFileName)) { Entry->me.Image = LoadIcns(Volume->RootDir, IconFileName, 128); - } // if + } else if ((StrLen(PathOnly) == 0) && (Volume->VolIconImage != NULL)) { + Entry->me.Image = Volume->VolIconImage; + } // icon matched to loader or volume Temp = FindLastDirName(LoaderPath); MergeStrings(&OSIconName, Temp, L','); @@ -552,6 +556,9 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Entry->OSType = 'R'; ShortcutLetter = 'R'; } else if (StriCmp(LoaderPath, MACOSX_LOADER_PATH) == 0) { + if (Volume->VolIconImage != NULL) { // custom icon file found + Entry->me.Image = Volume->VolIconImage; + } MergeStrings(&OSIconName, L"mac", L','); Entry->UseGraphicsMode = TRUE; Entry->OSType = 'M'; @@ -581,6 +588,8 @@ VOID SetLoaderDefaults(LOADER_ENTRY *Entry, CHAR16 *LoaderPath, IN REFIT_VOLUME Entry->me.ShortcutLetter = ShortcutLetter; if (Entry->me.Image == NULL) Entry->me.Image = LoadOSIcon(OSIconName, L"unknown", FALSE); + if (PathOnly != NULL) + FreePool(PathOnly); } // VOID SetLoaderDefaults() // Add a specified EFI boot loader to the list, using automatic settings -- 2.39.2