3 * Functions related to BIOS/CSM/legacy booting
5 * Copyright (c) 2006 Christoph Pfisterer
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Modifications copyright (c) 2012-2015 Roderick W. Smith
39 * Modifications distributed under the terms of the GNU General Public
40 * License (GPL) version 3 (GPLv3), a copy of which must be distributed
41 * with this source code or binaries made from it.
50 #include "refit_call_wrapper.h"
52 #include "syslinux_mbr.h"
53 #include "../EfiLib/BdsHelper.h"
54 #include "../EfiLib/legacy.h"
56 extern REFIT_MENU_ENTRY MenuEntryReturn
;
57 extern REFIT_MENU_SCREEN MainMenu
;
59 static EFI_STATUS
ActivateMbrPartition(IN EFI_BLOCK_IO
*BlockIO
, IN UINTN PartitionIndex
)
62 UINT8 SectorBuffer
[512];
63 MBR_PARTITION_INFO
*MbrTable
, *EMbrTable
;
64 UINT32 ExtBase
, ExtCurrent
, NextExtCurrent
;
65 UINTN LogicalPartitionIndex
= 4;
70 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
71 if (EFI_ERROR(Status
))
73 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
74 return EFI_NOT_FOUND
; // safety measure #1
76 // add boot code if necessary
78 for (i
= 0; i
< MBR_BOOTCODE_SIZE
; i
++) {
79 if (SectorBuffer
[i
] != 0) {
85 // no boot code found in the MBR, add the syslinux MBR code
86 SetMem(SectorBuffer
, MBR_BOOTCODE_SIZE
, 0);
87 CopyMem(SectorBuffer
, syslinux_mbr
, SYSLINUX_MBR_SIZE
);
90 // set the partition active
91 MbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
93 for (i
= 0; i
< 4; i
++) {
94 if (MbrTable
[i
].Flags
!= 0x00 && MbrTable
[i
].Flags
!= 0x80)
95 return EFI_NOT_FOUND
; // safety measure #2
96 if (i
== PartitionIndex
)
97 MbrTable
[i
].Flags
= 0x80;
98 else if (PartitionIndex
>= 4 && IS_EXTENDED_PART_TYPE(MbrTable
[i
].Type
)) {
99 MbrTable
[i
].Flags
= 0x80;
100 ExtBase
= MbrTable
[i
].StartLBA
;
102 MbrTable
[i
].Flags
= 0x00;
106 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
107 if (EFI_ERROR(Status
))
110 if (PartitionIndex
>= 4) {
111 // we have to activate a logical partition, so walk the EMBR chain
113 // NOTE: ExtBase was set above while looking at the MBR table
114 for (ExtCurrent
= ExtBase
; ExtCurrent
; ExtCurrent
= NextExtCurrent
) {
116 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
117 if (EFI_ERROR(Status
))
119 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
120 return EFI_NOT_FOUND
; // safety measure #3
122 // scan EMBR, set appropriate partition active
123 EMbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
125 for (i
= 0; i
< 4; i
++) {
126 if (EMbrTable
[i
].Flags
!= 0x00 && EMbrTable
[i
].Flags
!= 0x80)
127 return EFI_NOT_FOUND
; // safety measure #4
128 if (EMbrTable
[i
].StartLBA
== 0 || EMbrTable
[i
].Size
== 0)
130 if (IS_EXTENDED_PART_TYPE(EMbrTable
[i
].Type
)) {
132 NextExtCurrent
= ExtBase
+ EMbrTable
[i
].StartLBA
;
133 EMbrTable
[i
].Flags
= (PartitionIndex
>= LogicalPartitionIndex
) ? 0x80 : 0x00;
137 EMbrTable
[i
].Flags
= (PartitionIndex
== LogicalPartitionIndex
) ? 0x80 : 0x00;
138 LogicalPartitionIndex
++;
142 // write current EMBR
143 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
144 if (EFI_ERROR(Status
))
147 if (PartitionIndex
< LogicalPartitionIndex
)
148 break; // stop the loop, no need to touch further EMBRs
154 } /* static EFI_STATUS ActivateMbrPartition() */
156 static EFI_GUID AppleVariableVendorID
= { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 };
158 static EFI_STATUS
WriteBootDiskHint(IN EFI_DEVICE_PATH
*WholeDiskDevicePath
)
162 Status
= refit_call5_wrapper(RT
->SetVariable
, L
"BootCampHD", &AppleVariableVendorID
,
163 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
164 GetDevicePathSize(WholeDiskDevicePath
), WholeDiskDevicePath
);
165 if (EFI_ERROR(Status
))
171 // early 2006 Core Duo / Core Solo models
172 static UINT8 LegacyLoaderDevicePath1Data
[] = {
173 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
175 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
176 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
177 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
178 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
180 // mid-2006 Mac Pro (and probably other Core 2 models)
181 static UINT8 LegacyLoaderDevicePath2Data
[] = {
182 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
183 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
184 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
185 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
186 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
187 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
189 // mid-2007 MBP ("Santa Rosa" based models)
190 static UINT8 LegacyLoaderDevicePath3Data
[] = {
191 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
193 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
194 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
195 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
196 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
199 static UINT8 LegacyLoaderDevicePath4Data
[] = {
200 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
201 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
202 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
203 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
204 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
205 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
207 // late-2008 MB/MBP (NVidia chipset)
208 static UINT8 LegacyLoaderDevicePath5Data
[] = {
209 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
210 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
211 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
212 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
213 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
214 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
217 static EFI_DEVICE_PATH
*LegacyLoaderList
[] = {
218 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath1Data
,
219 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath2Data
,
220 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath3Data
,
221 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath4Data
,
222 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath5Data
,
226 #define MAX_DISCOVERED_PATHS (16)
228 VOID
StartLegacy(IN LEGACY_ENTRY
*Entry
, IN CHAR16
*SelectionName
)
231 EG_IMAGE
*BootLogoImage
;
232 UINTN ErrorInStep
= 0;
233 EFI_DEVICE_PATH
*DiscoveredPathList
[MAX_DISCOVERED_PATHS
];
235 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (Mac mode)");
237 BootLogoImage
= LoadOSIcon(Entry
->Volume
->OSIconName
, L
"legacy", TRUE
);
238 if (BootLogoImage
!= NULL
)
239 BltImageAlpha(BootLogoImage
,
240 (UGAWidth
- BootLogoImage
->Width
) >> 1,
241 (UGAHeight
- BootLogoImage
->Height
) >> 1,
242 &StdBackgroundPixel
);
244 if (Entry
->Volume
->IsMbrPartition
)
245 ActivateMbrPartition(Entry
->Volume
->WholeDiskBlockIO
, Entry
->Volume
->MbrPartitionIndex
);
247 if (Entry
->Volume
->DiskKind
!= DISK_KIND_OPTICAL
&& Entry
->Volume
->WholeDiskDevicePath
!= NULL
)
248 WriteBootDiskHint(Entry
->Volume
->WholeDiskDevicePath
);
250 ExtractLegacyLoaderPaths(DiscoveredPathList
, MAX_DISCOVERED_PATHS
, LegacyLoaderList
);
252 StoreLoaderName(SelectionName
);
253 Status
= StartEFIImageList(DiscoveredPathList
, Entry
->LoadOptions
, TYPE_LEGACY
, L
"legacy loader", 0, &ErrorInStep
, TRUE
, FALSE
);
254 if (Status
== EFI_NOT_FOUND
) {
255 if (ErrorInStep
== 1) {
256 Print(L
"\nPlease make sure that you have the latest firmware update installed.\n");
257 } else if (ErrorInStep
== 3) {
258 Print(L
"\nThe firmware refused to boot from the selected volume. Note that external\n"
259 L
"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
262 FinishExternalScreen();
263 } /* static VOID StartLegacy() */
265 // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
266 VOID
StartLegacyUEFI(LEGACY_ENTRY
*Entry
, CHAR16
*SelectionName
)
268 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (UEFI mode)");
269 StoreLoaderName(SelectionName
);
271 BdsLibConnectDevicePath (Entry
->BdsOption
->DevicePath
);
272 BdsLibDoLegacyBoot(Entry
->BdsOption
);
274 // If we get here, it means that there was a failure....
275 Print(L
"Failure booting legacy (BIOS) OS.");
277 FinishExternalScreen();
278 } // static VOID StartLegacyUEFI()
280 static LEGACY_ENTRY
* AddLegacyEntry(IN CHAR16
*LoaderTitle
, IN REFIT_VOLUME
*Volume
)
282 LEGACY_ENTRY
*Entry
, *SubEntry
;
283 REFIT_MENU_SCREEN
*SubScreen
;
284 CHAR16
*VolDesc
, *LegacyTitle
;
285 CHAR16 ShortcutLetter
= 0;
287 if (LoaderTitle
== NULL
) {
288 if (Volume
->OSName
!= NULL
) {
289 LoaderTitle
= Volume
->OSName
;
290 if (LoaderTitle
[0] == 'W' || LoaderTitle
[0] == 'L')
291 ShortcutLetter
= LoaderTitle
[0];
293 LoaderTitle
= L
"Legacy OS";
295 if (Volume
->VolName
!= NULL
)
296 VolDesc
= Volume
->VolName
;
298 VolDesc
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" : L
"HD";
300 LegacyTitle
= AllocateZeroPool(256 * sizeof(CHAR16
));
301 if (LegacyTitle
!= NULL
)
302 SPrint(LegacyTitle
, 255, L
"Boot %s from %s", LoaderTitle
, VolDesc
);
303 if (IsInSubstring(LegacyTitle
, GlobalConfig
.DontScanVolumes
)) {
304 MyFreePool(LegacyTitle
);
308 // prepare the menu entry
309 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
310 Entry
->me
.Title
= LegacyTitle
;
311 Entry
->me
.Tag
= TAG_LEGACY
;
313 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
314 Entry
->me
.Image
= LoadOSIcon(Volume
->OSIconName
, L
"legacy", FALSE
);
315 Entry
->me
.BadgeImage
= Volume
->VolBadgeImage
;
316 Entry
->Volume
= Volume
;
317 Entry
->LoadOptions
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" :
318 ((Volume
->DiskKind
== DISK_KIND_EXTERNAL
) ? L
"USB" : L
"HD");
319 Entry
->Enabled
= TRUE
;
321 // create the submenu
322 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
323 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
324 SPrint(SubScreen
->Title
, 255, L
"Boot Options for %s on %s", LoaderTitle
, VolDesc
);
325 SubScreen
->TitleImage
= Entry
->me
.Image
;
326 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
327 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
328 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
330 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
334 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
335 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
336 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LoaderTitle
);
337 SubEntry
->me
.Tag
= TAG_LEGACY
;
338 SubEntry
->Volume
= Entry
->Volume
;
339 SubEntry
->LoadOptions
= Entry
->LoadOptions
;
340 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
342 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
343 Entry
->me
.SubScreen
= SubScreen
;
344 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
346 } /* static LEGACY_ENTRY * AddLegacyEntry() */
350 Create a rEFInd boot option from a Legacy BIOS protocol option.
352 static LEGACY_ENTRY
* AddLegacyEntryUEFI(BDS_COMMON_OPTION
*BdsOption
, IN UINT16 DiskType
)
354 LEGACY_ENTRY
*Entry
, *SubEntry
;
355 REFIT_MENU_SCREEN
*SubScreen
;
356 CHAR16 ShortcutLetter
= 0;
357 CHAR16
*LegacyDescription
= StrDuplicate(BdsOption
->Description
);
359 if (IsInSubstring(LegacyDescription
, GlobalConfig
.DontScanVolumes
))
362 // Remove stray spaces, since many EFIs produce descriptions with lots of
363 // extra spaces, especially at the end; this throws off centering of the
364 // description on the screen....
365 LimitStringLength(LegacyDescription
, 100);
367 // prepare the menu entry
368 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
369 Entry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
370 SPrint(Entry
->me
.Title
, 255, L
"Boot legacy target %s", LegacyDescription
);
371 Entry
->me
.Tag
= TAG_LEGACY_UEFI
;
373 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
374 Entry
->me
.Image
= LoadOSIcon(L
"legacy", L
"legacy", TRUE
);
375 Entry
->LoadOptions
= (DiskType
== BBS_CDROM
) ? L
"CD" :
376 ((DiskType
== BBS_USB
) ? L
"USB" : L
"HD");
377 Entry
->me
.BadgeImage
= GetDiskBadge(DiskType
);
378 Entry
->BdsOption
= BdsOption
;
379 Entry
->Enabled
= TRUE
;
381 // create the submenu
382 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
383 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
384 SPrint(SubScreen
->Title
, 255, L
"No boot options for legacy target");
385 SubScreen
->TitleImage
= Entry
->me
.Image
;
386 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
387 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
388 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
390 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
394 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
395 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
396 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LegacyDescription
);
397 SubEntry
->me
.Tag
= TAG_LEGACY_UEFI
;
398 Entry
->BdsOption
= BdsOption
;
399 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
401 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
402 Entry
->me
.SubScreen
= SubScreen
;
403 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
405 } /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
408 Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
409 In testing, protocol has not been implemented on Macs but has been
410 implemented on most UEFI PCs.
411 Restricts output to disks of the specified DiskType.
413 static VOID
ScanLegacyUEFI(IN UINTN DiskType
)
416 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
417 UINT16
*BootOrder
= NULL
;
419 CHAR16 BootOption
[10];
420 UINTN BootOrderSize
= 0;
422 BDS_COMMON_OPTION
*BdsOption
;
424 BBS_BBS_DEVICE_PATH
*BbsDevicePath
= NULL
;
425 BOOLEAN SearchingForUsb
= FALSE
;
427 InitializeListHead (&TempList
);
428 ZeroMem (Buffer
, sizeof (Buffer
));
430 // If LegacyBios protocol is not implemented on this platform, then
431 //we do not support this type of legacy boot on this machine.
432 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
433 if (EFI_ERROR (Status
))
436 // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
437 // so we set DiskType inappropriately elsewhere in the program and
438 // "translate" it here.
439 if (DiskType
== BBS_USB
) {
440 DiskType
= BBS_HARDDISK
;
441 SearchingForUsb
= TRUE
;
444 // Grab the boot order
445 BootOrder
= BdsLibGetVariableAndSize(L
"BootOrder", &gEfiGlobalVariableGuid
, &BootOrderSize
);
446 if (BootOrder
== NULL
) {
451 while (Index
< BootOrderSize
/ sizeof (UINT16
))
453 // Grab each boot option variable from the boot order, and convert
454 // the variable into a BDS boot option
455 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
456 BdsOption
= BdsLibVariableToOption (&TempList
, BootOption
);
458 if (BdsOption
!= NULL
) {
459 BbsDevicePath
= (BBS_BBS_DEVICE_PATH
*)BdsOption
->DevicePath
;
460 // Only add the entry if it is of a requested type (e.g. USB, HD)
461 // Two checks necessary because some systems return EFI boot loaders
462 // with a DeviceType value that would inappropriately include them
463 // as legacy loaders....
464 if ((BbsDevicePath
->DeviceType
== DiskType
) && (BdsOption
->DevicePath
->Type
== DEVICE_TYPE_BIOS
)) {
465 // USB flash drives appear as hard disks with certain media flags set.
466 // Look for this, and if present, pass it on with the (technically
467 // incorrect, but internally useful) BBS_TYPE_USB flag set.
468 if (DiskType
== BBS_HARDDISK
) {
469 if (SearchingForUsb
&& (BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
470 AddLegacyEntryUEFI(BdsOption
, BBS_USB
);
471 } else if (!SearchingForUsb
&& !(BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
472 AddLegacyEntryUEFI(BdsOption
, DiskType
);
475 AddLegacyEntryUEFI(BdsOption
, DiskType
);
478 } // if (BdsOption != NULL)
481 } /* static VOID ScanLegacyUEFI() */
483 static VOID
ScanLegacyVolume(REFIT_VOLUME
*Volume
, UINTN VolumeIndex
) {
485 BOOLEAN ShowVolume
, HideIfOthersFound
;
488 HideIfOthersFound
= FALSE
;
489 if (Volume
->IsAppleLegacy
) {
491 HideIfOthersFound
= TRUE
;
492 } else if (Volume
->HasBootCode
) {
494 if (Volume
->BlockIO
== Volume
->WholeDiskBlockIO
&&
495 Volume
->BlockIOOffset
== 0 &&
496 Volume
->OSName
== NULL
)
497 // this is a whole disk (MBR) entry; hide if we have entries for partitions
498 HideIfOthersFound
= TRUE
;
500 if (HideIfOthersFound
) {
501 // check for other bootable entries on the same disk
502 for (VolumeIndex2
= 0; VolumeIndex2
< VolumesCount
; VolumeIndex2
++) {
503 if (VolumeIndex2
!= VolumeIndex
&& Volumes
[VolumeIndex2
]->HasBootCode
&&
504 Volumes
[VolumeIndex2
]->WholeDiskBlockIO
== Volume
->WholeDiskBlockIO
)
510 AddLegacyEntry(NULL
, Volume
);
511 } // static VOID ScanLegacyVolume()
513 // Scan attached optical discs for legacy (BIOS) boot code
514 // and add anything found to the list....
515 VOID
ScanLegacyDisc(VOID
)
518 REFIT_VOLUME
*Volume
;
520 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
521 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
522 Volume
= Volumes
[VolumeIndex
];
523 if (Volume
->DiskKind
== DISK_KIND_OPTICAL
)
524 ScanLegacyVolume(Volume
, VolumeIndex
);
526 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
527 ScanLegacyUEFI(BBS_CDROM
);
529 } /* VOID ScanLegacyDisc() */
531 // Scan internal hard disks for legacy (BIOS) boot code
532 // and add anything found to the list....
533 VOID
ScanLegacyInternal(VOID
)
536 REFIT_VOLUME
*Volume
;
538 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
539 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
540 Volume
= Volumes
[VolumeIndex
];
541 if (Volume
->DiskKind
== DISK_KIND_INTERNAL
)
542 ScanLegacyVolume(Volume
, VolumeIndex
);
544 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
545 // TODO: This actually picks up USB flash drives, too; try to find
546 // a way to differentiate the two....
547 ScanLegacyUEFI(BBS_HARDDISK
);
549 } /* VOID ScanLegacyInternal() */
551 // Scan external disks for legacy (BIOS) boot code
552 // and add anything found to the list....
553 VOID
ScanLegacyExternal(VOID
)
556 REFIT_VOLUME
*Volume
;
558 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
559 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
560 Volume
= Volumes
[VolumeIndex
];
561 if (Volume
->DiskKind
== DISK_KIND_EXTERNAL
)
562 ScanLegacyVolume(Volume
, VolumeIndex
);
564 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
565 // TODO: This actually doesn't do anything useful; leaving in hopes of
566 // fixing it later....
567 ScanLegacyUEFI(BBS_USB
);
569 } /* VOID ScanLegacyExternal() */
571 // Determine what (if any) type of legacy (BIOS) boot support is available
572 VOID
FindLegacyBootType(VOID
) {
574 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
576 GlobalConfig
.LegacyType
= LEGACY_TYPE_NONE
;
578 // UEFI-style legacy BIOS support is available only with some EFI implementations....
579 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
580 if (!EFI_ERROR (Status
))
581 GlobalConfig
.LegacyType
= LEGACY_TYPE_UEFI
;
583 // Macs have their own system. If the firmware vendor code contains the
584 // string "Apple", assume it's available. Note that this overrides the
585 // UEFI type, and might yield false positives if the vendor string
586 // contains "Apple" as part of something bigger, so this isn't 100%
588 if (StriSubCmp(L
"Apple", ST
->FirmwareVendor
))
589 GlobalConfig
.LegacyType
= LEGACY_TYPE_MAC
;
590 } // VOID FindLegacyBootType
592 // Warn the user if legacy OS scans are enabled but the firmware can't support them....
593 VOID
WarnIfLegacyProblems(VOID
) {
594 BOOLEAN found
= FALSE
;
597 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_NONE
) {
599 if (GlobalConfig
.ScanFor
[i
] == 'h' || GlobalConfig
.ScanFor
[i
] == 'b' || GlobalConfig
.ScanFor
[i
] == 'c' ||
600 GlobalConfig
.ScanFor
[i
] == 'H' || GlobalConfig
.ScanFor
[i
] == 'B' || GlobalConfig
.ScanFor
[i
] == 'C')
603 } while ((i
< NUM_SCAN_OPTIONS
) && (!found
));
606 Print(L
"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
607 Print(L
"(BIOS) boot options; however, this is not possible because your computer lacks\n");
608 Print(L
"the necessary Compatibility Support Module (CSM) support or that support is\n");
609 Print(L
"disabled in your firmware.\n");
612 } // if no legacy support
613 } // VOID WarnIfLegacyProblems()