--- /dev/null
+/*
+ * refind/legacy.c
+ * Functions related to BIOS/CSM/legacy booting
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), a copy of which must be distributed
+ * with this source code or binaries made from it.
+ *
+ */
+
+#include "global.h"
+#include "icns.h"
+#include "legacy.h"
+#include "lib.h"
+#include "menu.h"
+#include "refit_call_wrapper.h"
+#include "screen.h"
+#include "syslinux_mbr.h"
+#include "../EfiLib/BdsHelper.h"
+#include "../EfiLib/legacy.h"
+
+extern REFIT_MENU_ENTRY MenuEntryReturn;
+extern REFIT_MENU_SCREEN MainMenu;
+
+static EFI_STATUS ActivateMbrPartition(IN EFI_BLOCK_IO *BlockIO, IN UINTN PartitionIndex)
+{
+ EFI_STATUS Status;
+ UINT8 SectorBuffer[512];
+ MBR_PARTITION_INFO *MbrTable, *EMbrTable;
+ UINT32 ExtBase, ExtCurrent, NextExtCurrent;
+ UINTN LogicalPartitionIndex = 4;
+ UINTN i;
+ BOOLEAN HaveBootCode;
+
+ // read MBR
+ Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer);
+ if (EFI_ERROR(Status))
+ return Status;
+ if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
+ return EFI_NOT_FOUND; // safety measure #1
+
+ // add boot code if necessary
+ HaveBootCode = FALSE;
+ for (i = 0; i < MBR_BOOTCODE_SIZE; i++) {
+ if (SectorBuffer[i] != 0) {
+ HaveBootCode = TRUE;
+ break;
+ }
+ }
+ if (!HaveBootCode) {
+ // no boot code found in the MBR, add the syslinux MBR code
+ SetMem(SectorBuffer, MBR_BOOTCODE_SIZE, 0);
+ CopyMem(SectorBuffer, syslinux_mbr, SYSLINUX_MBR_SIZE);
+ }
+
+ // set the partition active
+ MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
+ ExtBase = 0;
+ for (i = 0; i < 4; i++) {
+ if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80)
+ return EFI_NOT_FOUND; // safety measure #2
+ if (i == PartitionIndex)
+ MbrTable[i].Flags = 0x80;
+ else if (PartitionIndex >= 4 && IS_EXTENDED_PART_TYPE(MbrTable[i].Type)) {
+ MbrTable[i].Flags = 0x80;
+ ExtBase = MbrTable[i].StartLBA;
+ } else
+ MbrTable[i].Flags = 0x00;
+ }
+
+ // write MBR
+ Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, 0, 512, SectorBuffer);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ if (PartitionIndex >= 4) {
+ // we have to activate a logical partition, so walk the EMBR chain
+
+ // NOTE: ExtBase was set above while looking at the MBR table
+ for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) {
+ // read current EMBR
+ Status = refit_call5_wrapper(BlockIO->ReadBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer);
+ if (EFI_ERROR(Status))
+ return Status;
+ if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
+ return EFI_NOT_FOUND; // safety measure #3
+
+ // scan EMBR, set appropriate partition active
+ EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
+ NextExtCurrent = 0;
+ for (i = 0; i < 4; i++) {
+ if (EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80)
+ return EFI_NOT_FOUND; // safety measure #4
+ if (EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0)
+ break;
+ if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) {
+ // link to next EMBR
+ NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
+ EMbrTable[i].Flags = (PartitionIndex >= LogicalPartitionIndex) ? 0x80 : 0x00;
+ break;
+ } else {
+ // logical partition
+ EMbrTable[i].Flags = (PartitionIndex == LogicalPartitionIndex) ? 0x80 : 0x00;
+ LogicalPartitionIndex++;
+ }
+ }
+
+ // write current EMBR
+ Status = refit_call5_wrapper(BlockIO->WriteBlocks, BlockIO, BlockIO->Media->MediaId, ExtCurrent, 512, SectorBuffer);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ if (PartitionIndex < LogicalPartitionIndex)
+ break; // stop the loop, no need to touch further EMBRs
+ }
+
+ }
+
+ return EFI_SUCCESS;
+} /* static EFI_STATUS ActivateMbrPartition() */
+
+static EFI_GUID AppleVariableVendorID = { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 };
+
+static EFI_STATUS WriteBootDiskHint(IN EFI_DEVICE_PATH *WholeDiskDevicePath)
+{
+ EFI_STATUS Status;
+
+ Status = refit_call5_wrapper(RT->SetVariable, L"BootCampHD", &AppleVariableVendorID,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ GetDevicePathSize(WholeDiskDevicePath), WholeDiskDevicePath);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ return EFI_SUCCESS;
+}
+
+// early 2006 Core Duo / Core Solo models
+static UINT8 LegacyLoaderDevicePath1Data[] = {
+ 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+ 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+ 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// mid-2006 Mac Pro (and probably other Core 2 models)
+static UINT8 LegacyLoaderDevicePath2Data[] = {
+ 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+ 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+ 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// mid-2007 MBP ("Santa Rosa" based models)
+static UINT8 LegacyLoaderDevicePath3Data[] = {
+ 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+ 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+ 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// early-2008 MBA
+static UINT8 LegacyLoaderDevicePath4Data[] = {
+ 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+ 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+ 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+// late-2008 MB/MBP (NVidia chipset)
+static UINT8 LegacyLoaderDevicePath5Data[] = {
+ 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+ 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+ 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+static EFI_DEVICE_PATH *LegacyLoaderList[] = {
+ (EFI_DEVICE_PATH *)LegacyLoaderDevicePath1Data,
+ (EFI_DEVICE_PATH *)LegacyLoaderDevicePath2Data,
+ (EFI_DEVICE_PATH *)LegacyLoaderDevicePath3Data,
+ (EFI_DEVICE_PATH *)LegacyLoaderDevicePath4Data,
+ (EFI_DEVICE_PATH *)LegacyLoaderDevicePath5Data,
+ NULL
+};
+
+#define MAX_DISCOVERED_PATHS (16)
+
+VOID StartLegacy(IN LEGACY_ENTRY *Entry, IN CHAR16 *SelectionName)
+{
+ EFI_STATUS Status;
+ EG_IMAGE *BootLogoImage;
+ UINTN ErrorInStep = 0;
+ EFI_DEVICE_PATH *DiscoveredPathList[MAX_DISCOVERED_PATHS];
+
+ BeginExternalScreen(TRUE, L"Booting Legacy OS (Mac mode)");
+
+ BootLogoImage = LoadOSIcon(Entry->Volume->OSIconName, L"legacy", TRUE);
+ if (BootLogoImage != NULL)
+ BltImageAlpha(BootLogoImage,
+ (UGAWidth - BootLogoImage->Width ) >> 1,
+ (UGAHeight - BootLogoImage->Height) >> 1,
+ &StdBackgroundPixel);
+
+ if (Entry->Volume->IsMbrPartition)
+ ActivateMbrPartition(Entry->Volume->WholeDiskBlockIO, Entry->Volume->MbrPartitionIndex);
+
+ if (Entry->Volume->DiskKind != DISK_KIND_OPTICAL && Entry->Volume->WholeDiskDevicePath != NULL)
+ WriteBootDiskHint(Entry->Volume->WholeDiskDevicePath);
+
+ ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList);
+
+ StoreLoaderName(SelectionName);
+ Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, TYPE_LEGACY, L"legacy loader", 0, &ErrorInStep, TRUE, FALSE);
+ if (Status == EFI_NOT_FOUND) {
+ if (ErrorInStep == 1) {
+ Print(L"\nPlease make sure that you have the latest firmware update installed.\n");
+ } else if (ErrorInStep == 3) {
+ Print(L"\nThe firmware refused to boot from the selected volume. Note that external\n"
+ L"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
+ }
+ }
+ FinishExternalScreen();
+} /* static VOID StartLegacy() */
+
+// Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
+VOID StartLegacyUEFI(LEGACY_ENTRY *Entry, CHAR16 *SelectionName)
+{
+ BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)");
+ StoreLoaderName(SelectionName);
+
+ BdsLibConnectDevicePath (Entry->BdsOption->DevicePath);
+ BdsLibDoLegacyBoot(Entry->BdsOption);
+
+ // If we get here, it means that there was a failure....
+ Print(L"Failure booting legacy (BIOS) OS.");
+ PauseForKey();
+ FinishExternalScreen();
+} // static VOID StartLegacyUEFI()
+
+static LEGACY_ENTRY * AddLegacyEntry(IN CHAR16 *LoaderTitle, IN REFIT_VOLUME *Volume)
+{
+ LEGACY_ENTRY *Entry, *SubEntry;
+ REFIT_MENU_SCREEN *SubScreen;
+ CHAR16 *VolDesc, *LegacyTitle;
+ CHAR16 ShortcutLetter = 0;
+
+ if (LoaderTitle == NULL) {
+ if (Volume->OSName != NULL) {
+ LoaderTitle = Volume->OSName;
+ if (LoaderTitle[0] == 'W' || LoaderTitle[0] == 'L')
+ ShortcutLetter = LoaderTitle[0];
+ } else
+ LoaderTitle = L"Legacy OS";
+ }
+ if (Volume->VolName != NULL)
+ VolDesc = Volume->VolName;
+ else
+ VolDesc = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" : L"HD";
+
+ LegacyTitle = AllocateZeroPool(256 * sizeof(CHAR16));
+ if (LegacyTitle != NULL)
+ SPrint(LegacyTitle, 255, L"Boot %s from %s", LoaderTitle, VolDesc);
+ if (IsInSubstring(LegacyTitle, GlobalConfig.DontScanVolumes)) {
+ MyFreePool(LegacyTitle);
+ return NULL;
+ } // if
+
+ // prepare the menu entry
+ Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+ Entry->me.Title = LegacyTitle;
+ Entry->me.Tag = TAG_LEGACY;
+ Entry->me.Row = 0;
+ Entry->me.ShortcutLetter = ShortcutLetter;
+ Entry->me.Image = LoadOSIcon(Volume->OSIconName, L"legacy", FALSE);
+ Entry->me.BadgeImage = Volume->VolBadgeImage;
+ Entry->Volume = Volume;
+ Entry->LoadOptions = (Volume->DiskKind == DISK_KIND_OPTICAL) ? L"CD" :
+ ((Volume->DiskKind == DISK_KIND_EXTERNAL) ? L"USB" : L"HD");
+ Entry->Enabled = TRUE;
+
+ // create the submenu
+ SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+ SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(SubScreen->Title, 255, L"Boot Options for %s on %s", LoaderTitle, VolDesc);
+ SubScreen->TitleImage = Entry->me.Image;
+ SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+ if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+ SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+ } else {
+ SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+ } // if/else
+
+ // default entry
+ SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+ SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(SubEntry->me.Title, 255, L"Boot %s", LoaderTitle);
+ SubEntry->me.Tag = TAG_LEGACY;
+ SubEntry->Volume = Entry->Volume;
+ SubEntry->LoadOptions = Entry->LoadOptions;
+ AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+
+ AddMenuEntry(SubScreen, &MenuEntryReturn);
+ Entry->me.SubScreen = SubScreen;
+ AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+ return Entry;
+} /* static LEGACY_ENTRY * AddLegacyEntry() */
+
+
+/**
+ Create a rEFInd boot option from a Legacy BIOS protocol option.
+*/
+static LEGACY_ENTRY * AddLegacyEntryUEFI(BDS_COMMON_OPTION *BdsOption, IN UINT16 DiskType)
+{
+ LEGACY_ENTRY *Entry, *SubEntry;
+ REFIT_MENU_SCREEN *SubScreen;
+ CHAR16 ShortcutLetter = 0;
+ CHAR16 *LegacyDescription = StrDuplicate(BdsOption->Description);
+
+ if (IsInSubstring(LegacyDescription, GlobalConfig.DontScanVolumes))
+ return NULL;
+
+ // Remove stray spaces, since many EFIs produce descriptions with lots of
+ // extra spaces, especially at the end; this throws off centering of the
+ // description on the screen....
+ LimitStringLength(LegacyDescription, 100);
+
+ // prepare the menu entry
+ Entry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+ Entry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(Entry->me.Title, 255, L"Boot legacy target %s", LegacyDescription);
+ Entry->me.Tag = TAG_LEGACY_UEFI;
+ Entry->me.Row = 0;
+ Entry->me.ShortcutLetter = ShortcutLetter;
+ Entry->me.Image = LoadOSIcon(L"legacy", L"legacy", TRUE);
+ Entry->LoadOptions = (DiskType == BBS_CDROM) ? L"CD" :
+ ((DiskType == BBS_USB) ? L"USB" : L"HD");
+ Entry->me.BadgeImage = GetDiskBadge(DiskType);
+ Entry->BdsOption = BdsOption;
+ Entry->Enabled = TRUE;
+
+ // create the submenu
+ SubScreen = AllocateZeroPool(sizeof(REFIT_MENU_SCREEN));
+ SubScreen->Title = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(SubScreen->Title, 255, L"No boot options for legacy target");
+ SubScreen->TitleImage = Entry->me.Image;
+ SubScreen->Hint1 = StrDuplicate(SUBSCREEN_HINT1);
+ if (GlobalConfig.HideUIFlags & HIDEUI_FLAG_EDITOR) {
+ SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR);
+ } else {
+ SubScreen->Hint2 = StrDuplicate(SUBSCREEN_HINT2);
+ } // if/else
+
+ // default entry
+ SubEntry = AllocateZeroPool(sizeof(LEGACY_ENTRY));
+ SubEntry->me.Title = AllocateZeroPool(256 * sizeof(CHAR16));
+ SPrint(SubEntry->me.Title, 255, L"Boot %s", LegacyDescription);
+ SubEntry->me.Tag = TAG_LEGACY_UEFI;
+ Entry->BdsOption = BdsOption;
+ AddMenuEntry(SubScreen, (REFIT_MENU_ENTRY *)SubEntry);
+
+ AddMenuEntry(SubScreen, &MenuEntryReturn);
+ Entry->me.SubScreen = SubScreen;
+ AddMenuEntry(&MainMenu, (REFIT_MENU_ENTRY *)Entry);
+ return Entry;
+} /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
+
+/**
+ Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
+ In testing, protocol has not been implemented on Macs but has been
+ implemented on most UEFI PCs.
+ Restricts output to disks of the specified DiskType.
+*/
+static VOID ScanLegacyUEFI(IN UINTN DiskType)
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 *BootOrder = NULL;
+ UINTN Index = 0;
+ CHAR16 BootOption[10];
+ UINTN BootOrderSize = 0;
+ CHAR16 Buffer[20];
+ BDS_COMMON_OPTION *BdsOption;
+ LIST_ENTRY TempList;
+ BBS_BBS_DEVICE_PATH *BbsDevicePath = NULL;
+ BOOLEAN SearchingForUsb = FALSE;
+
+ InitializeListHead (&TempList);
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ // If LegacyBios protocol is not implemented on this platform, then
+ //we do not support this type of legacy boot on this machine.
+ Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status))
+ return;
+
+ // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
+ // so we set DiskType inappropriately elsewhere in the program and
+ // "translate" it here.
+ if (DiskType == BBS_USB) {
+ DiskType = BBS_HARDDISK;
+ SearchingForUsb = TRUE;
+ } // if
+
+ // Grab the boot order
+ BootOrder = BdsLibGetVariableAndSize(L"BootOrder", &gEfiGlobalVariableGuid, &BootOrderSize);
+ if (BootOrder == NULL) {
+ BootOrderSize = 0;
+ }
+
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16))
+ {
+ // Grab each boot option variable from the boot order, and convert
+ // the variable into a BDS boot option
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BdsOption = BdsLibVariableToOption (&TempList, BootOption);
+
+ if (BdsOption != NULL) {
+ BbsDevicePath = (BBS_BBS_DEVICE_PATH *)BdsOption->DevicePath;
+ // Only add the entry if it is of a requested type (e.g. USB, HD)
+ // Two checks necessary because some systems return EFI boot loaders
+ // with a DeviceType value that would inappropriately include them
+ // as legacy loaders....
+ if ((BbsDevicePath->DeviceType == DiskType) && (BdsOption->DevicePath->Type == DEVICE_TYPE_BIOS)) {
+ // USB flash drives appear as hard disks with certain media flags set.
+ // Look for this, and if present, pass it on with the (technically
+ // incorrect, but internally useful) BBS_TYPE_USB flag set.
+ if (DiskType == BBS_HARDDISK) {
+ if (SearchingForUsb && (BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) {
+ AddLegacyEntryUEFI(BdsOption, BBS_USB);
+ } else if (!SearchingForUsb && !(BbsDevicePath->StatusFlag & (BBS_MEDIA_PRESENT | BBS_MEDIA_MAYBE_PRESENT))) {
+ AddLegacyEntryUEFI(BdsOption, DiskType);
+ }
+ } else {
+ AddLegacyEntryUEFI(BdsOption, DiskType);
+ } // if/else
+ } // if
+ } // if (BdsOption != NULL)
+ Index++;
+ } // while
+} /* static VOID ScanLegacyUEFI() */
+
+static VOID ScanLegacyVolume(REFIT_VOLUME *Volume, UINTN VolumeIndex) {
+ UINTN VolumeIndex2;
+ BOOLEAN ShowVolume, HideIfOthersFound;
+
+ ShowVolume = FALSE;
+ HideIfOthersFound = FALSE;
+ if (Volume->IsAppleLegacy) {
+ ShowVolume = TRUE;
+ HideIfOthersFound = TRUE;
+ } else if (Volume->HasBootCode) {
+ ShowVolume = TRUE;
+ if (Volume->BlockIO == Volume->WholeDiskBlockIO &&
+ Volume->BlockIOOffset == 0 &&
+ Volume->OSName == NULL)
+ // this is a whole disk (MBR) entry; hide if we have entries for partitions
+ HideIfOthersFound = TRUE;
+ }
+ if (HideIfOthersFound) {
+ // check for other bootable entries on the same disk
+ for (VolumeIndex2 = 0; VolumeIndex2 < VolumesCount; VolumeIndex2++) {
+ if (VolumeIndex2 != VolumeIndex && Volumes[VolumeIndex2]->HasBootCode &&
+ Volumes[VolumeIndex2]->WholeDiskBlockIO == Volume->WholeDiskBlockIO)
+ ShowVolume = FALSE;
+ }
+ }
+
+ if (ShowVolume)
+ AddLegacyEntry(NULL, Volume);
+} // static VOID ScanLegacyVolume()
+
+// Scan attached optical discs for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyDisc(VOID)
+{
+ UINTN VolumeIndex;
+ REFIT_VOLUME *Volume;
+
+ if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ Volume = Volumes[VolumeIndex];
+ if (Volume->DiskKind == DISK_KIND_OPTICAL)
+ ScanLegacyVolume(Volume, VolumeIndex);
+ } // for
+ } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+ ScanLegacyUEFI(BBS_CDROM);
+ }
+} /* VOID ScanLegacyDisc() */
+
+// Scan internal hard disks for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyInternal(VOID)
+{
+ UINTN VolumeIndex;
+ REFIT_VOLUME *Volume;
+
+ if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ Volume = Volumes[VolumeIndex];
+ if (Volume->DiskKind == DISK_KIND_INTERNAL)
+ ScanLegacyVolume(Volume, VolumeIndex);
+ } // for
+ } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+ // TODO: This actually picks up USB flash drives, too; try to find
+ // a way to differentiate the two....
+ ScanLegacyUEFI(BBS_HARDDISK);
+ }
+} /* VOID ScanLegacyInternal() */
+
+// Scan external disks for legacy (BIOS) boot code
+// and add anything found to the list....
+VOID ScanLegacyExternal(VOID)
+{
+ UINTN VolumeIndex;
+ REFIT_VOLUME *Volume;
+
+ if (GlobalConfig.LegacyType == LEGACY_TYPE_MAC) {
+ for (VolumeIndex = 0; VolumeIndex < VolumesCount; VolumeIndex++) {
+ Volume = Volumes[VolumeIndex];
+ if (Volume->DiskKind == DISK_KIND_EXTERNAL)
+ ScanLegacyVolume(Volume, VolumeIndex);
+ } // for
+ } else if (GlobalConfig.LegacyType == LEGACY_TYPE_UEFI) {
+ // TODO: This actually doesn't do anything useful; leaving in hopes of
+ // fixing it later....
+ ScanLegacyUEFI(BBS_USB);
+ }
+} /* VOID ScanLegacyExternal() */
+
+// Determine what (if any) type of legacy (BIOS) boot support is available
+VOID FindLegacyBootType(VOID) {
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ GlobalConfig.LegacyType = LEGACY_TYPE_NONE;
+
+ // UEFI-style legacy BIOS support is available only with some EFI implementations....
+ Status = refit_call3_wrapper(gBS->LocateProtocol, &gEfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (!EFI_ERROR (Status))
+ GlobalConfig.LegacyType = LEGACY_TYPE_UEFI;
+
+ // Macs have their own system. If the firmware vendor code contains the
+ // string "Apple", assume it's available. Note that this overrides the
+ // UEFI type, and might yield false positives if the vendor string
+ // contains "Apple" as part of something bigger, so this isn't 100%
+ // perfect.
+ if (StriSubCmp(L"Apple", ST->FirmwareVendor))
+ GlobalConfig.LegacyType = LEGACY_TYPE_MAC;
+} // VOID FindLegacyBootType
+
+// Warn the user if legacy OS scans are enabled but the firmware can't support them....
+VOID WarnIfLegacyProblems(VOID) {
+ BOOLEAN found = FALSE;
+ UINTN i = 0;
+
+ if (GlobalConfig.LegacyType == LEGACY_TYPE_NONE) {
+ do {
+ if (GlobalConfig.ScanFor[i] == 'h' || GlobalConfig.ScanFor[i] == 'b' || GlobalConfig.ScanFor[i] == 'c' ||
+ GlobalConfig.ScanFor[i] == 'H' || GlobalConfig.ScanFor[i] == 'B' || GlobalConfig.ScanFor[i] == 'C')
+ found = TRUE;
+ i++;
+ } while ((i < NUM_SCAN_OPTIONS) && (!found));
+
+ if (found) {
+ Print(L"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
+ Print(L"(BIOS) boot options; however, this is not possible because your computer lacks\n");
+ Print(L"the necessary Compatibility Support Module (CSM) support or that support is\n");
+ Print(L"disabled in your firmware.\n");
+ PauseForKey();
+ } // if (found)
+ } // if no legacy support
+} // VOID WarnIfLegacyProblems()
+