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"
57 extern REFIT_MENU_ENTRY MenuEntryReturn
;
58 extern REFIT_MENU_SCREEN MainMenu
;
60 #ifndef __MAKEWITH_GNUEFI
61 #define LibLocateHandle gBS->LocateHandleBuffer
62 #define DevicePathProtocol gEfiDevicePathProtocolGuid
65 static EFI_STATUS
ActivateMbrPartition(IN EFI_BLOCK_IO
*BlockIO
, IN UINTN PartitionIndex
)
68 UINT8 SectorBuffer
[512];
69 MBR_PARTITION_INFO
*MbrTable
, *EMbrTable
;
70 UINT32 ExtBase
, ExtCurrent
, NextExtCurrent
;
71 UINTN LogicalPartitionIndex
= 4;
76 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
77 if (EFI_ERROR(Status
))
79 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
80 return EFI_NOT_FOUND
; // safety measure #1
82 // add boot code if necessary
84 for (i
= 0; i
< MBR_BOOTCODE_SIZE
; i
++) {
85 if (SectorBuffer
[i
] != 0) {
91 // no boot code found in the MBR, add the syslinux MBR code
92 SetMem(SectorBuffer
, MBR_BOOTCODE_SIZE
, 0);
93 CopyMem(SectorBuffer
, syslinux_mbr
, SYSLINUX_MBR_SIZE
);
96 // set the partition active
97 MbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
99 for (i
= 0; i
< 4; i
++) {
100 if (MbrTable
[i
].Flags
!= 0x00 && MbrTable
[i
].Flags
!= 0x80)
101 return EFI_NOT_FOUND
; // safety measure #2
102 if (i
== PartitionIndex
)
103 MbrTable
[i
].Flags
= 0x80;
104 else if (PartitionIndex
>= 4 && IS_EXTENDED_PART_TYPE(MbrTable
[i
].Type
)) {
105 MbrTable
[i
].Flags
= 0x80;
106 ExtBase
= MbrTable
[i
].StartLBA
;
108 MbrTable
[i
].Flags
= 0x00;
112 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
113 if (EFI_ERROR(Status
))
116 if (PartitionIndex
>= 4) {
117 // we have to activate a logical partition, so walk the EMBR chain
119 // NOTE: ExtBase was set above while looking at the MBR table
120 for (ExtCurrent
= ExtBase
; ExtCurrent
; ExtCurrent
= NextExtCurrent
) {
122 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
123 if (EFI_ERROR(Status
))
125 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
126 return EFI_NOT_FOUND
; // safety measure #3
128 // scan EMBR, set appropriate partition active
129 EMbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
131 for (i
= 0; i
< 4; i
++) {
132 if (EMbrTable
[i
].Flags
!= 0x00 && EMbrTable
[i
].Flags
!= 0x80)
133 return EFI_NOT_FOUND
; // safety measure #4
134 if (EMbrTable
[i
].StartLBA
== 0 || EMbrTable
[i
].Size
== 0)
136 if (IS_EXTENDED_PART_TYPE(EMbrTable
[i
].Type
)) {
138 NextExtCurrent
= ExtBase
+ EMbrTable
[i
].StartLBA
;
139 EMbrTable
[i
].Flags
= (PartitionIndex
>= LogicalPartitionIndex
) ? 0x80 : 0x00;
143 EMbrTable
[i
].Flags
= (PartitionIndex
== LogicalPartitionIndex
) ? 0x80 : 0x00;
144 LogicalPartitionIndex
++;
148 // write current EMBR
149 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
150 if (EFI_ERROR(Status
))
153 if (PartitionIndex
< LogicalPartitionIndex
)
154 break; // stop the loop, no need to touch further EMBRs
160 } /* static EFI_STATUS ActivateMbrPartition() */
162 static EFI_GUID AppleVariableVendorID
= { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 };
164 static EFI_STATUS
WriteBootDiskHint(IN EFI_DEVICE_PATH
*WholeDiskDevicePath
)
168 Status
= refit_call5_wrapper(RT
->SetVariable
, L
"BootCampHD", &AppleVariableVendorID
,
169 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
170 GetDevicePathSize(WholeDiskDevicePath
), WholeDiskDevicePath
);
171 if (EFI_ERROR(Status
))
178 // firmware device path discovery
181 static UINT8 LegacyLoaderMediaPathData
[] = {
182 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
183 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
184 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
186 static EFI_DEVICE_PATH
*LegacyLoaderMediaPath
= (EFI_DEVICE_PATH
*)LegacyLoaderMediaPathData
;
188 static VOID
ExtractLegacyLoaderPaths(EFI_DEVICE_PATH
**PathList
, UINTN MaxPaths
, EFI_DEVICE_PATH
**HardcodedPathList
)
191 UINTN HandleCount
= 0;
192 UINTN HandleIndex
, HardcodedIndex
;
197 EFI_LOADED_IMAGE
*LoadedImage
;
198 EFI_DEVICE_PATH
*DevicePath
;
201 MaxPaths
--; // leave space for the terminating NULL pointer
203 // get all LoadedImage handles
204 Status
= LibLocateHandle(ByProtocol
, &LoadedImageProtocol
, NULL
, &HandleCount
, &Handles
);
205 if (CheckError(Status
, L
"while listing LoadedImage handles")) {
206 if (HardcodedPathList
) {
207 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
208 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
210 PathList
[PathCount
] = NULL
;
213 for (HandleIndex
= 0; HandleIndex
< HandleCount
&& PathCount
< MaxPaths
; HandleIndex
++) {
214 Handle
= Handles
[HandleIndex
];
216 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Handle
, &LoadedImageProtocol
, (VOID
**) &LoadedImage
);
217 if (EFI_ERROR(Status
))
218 continue; // This can only happen if the firmware scewed up, ignore it.
220 Status
= refit_call3_wrapper(BS
->HandleProtocol
, LoadedImage
->DeviceHandle
, &DevicePathProtocol
, (VOID
**) &DevicePath
);
221 if (EFI_ERROR(Status
))
222 continue; // This happens, ignore it.
224 // Only grab memory range nodes
225 if (DevicePathType(DevicePath
) != HARDWARE_DEVICE_PATH
|| DevicePathSubType(DevicePath
) != HW_MEMMAP_DP
)
228 // Check if we have this device path in the list already
229 // WARNING: This assumes the first node in the device path is unique!
231 for (PathIndex
= 0; PathIndex
< PathCount
; PathIndex
++) {
232 if (DevicePathNodeLength(DevicePath
) != DevicePathNodeLength(PathList
[PathIndex
]))
234 if (CompareMem(DevicePath
, PathList
[PathIndex
], DevicePathNodeLength(DevicePath
)) == 0) {
242 PathList
[PathCount
++] = AppendDevicePath(DevicePath
, LegacyLoaderMediaPath
);
246 if (HardcodedPathList
) {
247 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
248 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
250 PathList
[PathCount
] = NULL
;
251 } /* VOID ExtractLegacyLoaderPaths() */
253 // early 2006 Core Duo / Core Solo models
254 static UINT8 LegacyLoaderDevicePath1Data
[] = {
255 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
257 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
258 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
259 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
260 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
262 // mid-2006 Mac Pro (and probably other Core 2 models)
263 static UINT8 LegacyLoaderDevicePath2Data
[] = {
264 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
266 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
267 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
268 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
269 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
271 // mid-2007 MBP ("Santa Rosa" based models)
272 static UINT8 LegacyLoaderDevicePath3Data
[] = {
273 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
274 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
275 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
276 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
277 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
278 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
281 static UINT8 LegacyLoaderDevicePath4Data
[] = {
282 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
283 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
284 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
285 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
286 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
287 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
289 // late-2008 MB/MBP (NVidia chipset)
290 static UINT8 LegacyLoaderDevicePath5Data
[] = {
291 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
292 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
293 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
294 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
295 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
296 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
299 static EFI_DEVICE_PATH
*LegacyLoaderList
[] = {
300 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath1Data
,
301 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath2Data
,
302 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath3Data
,
303 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath4Data
,
304 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath5Data
,
308 #define MAX_DISCOVERED_PATHS (16)
310 VOID
StartLegacy(IN LEGACY_ENTRY
*Entry
, IN CHAR16
*SelectionName
)
313 EG_IMAGE
*BootLogoImage
;
314 UINTN ErrorInStep
= 0;
315 EFI_DEVICE_PATH
*DiscoveredPathList
[MAX_DISCOVERED_PATHS
];
317 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (Mac mode)");
319 BootLogoImage
= LoadOSIcon(Entry
->Volume
->OSIconName
, L
"legacy", TRUE
);
320 if (BootLogoImage
!= NULL
)
321 BltImageAlpha(BootLogoImage
,
322 (UGAWidth
- BootLogoImage
->Width
) >> 1,
323 (UGAHeight
- BootLogoImage
->Height
) >> 1,
324 &StdBackgroundPixel
);
326 if (Entry
->Volume
->IsMbrPartition
)
327 ActivateMbrPartition(Entry
->Volume
->WholeDiskBlockIO
, Entry
->Volume
->MbrPartitionIndex
);
329 if (Entry
->Volume
->DiskKind
!= DISK_KIND_OPTICAL
&& Entry
->Volume
->WholeDiskDevicePath
!= NULL
)
330 WriteBootDiskHint(Entry
->Volume
->WholeDiskDevicePath
);
332 ExtractLegacyLoaderPaths(DiscoveredPathList
, MAX_DISCOVERED_PATHS
, LegacyLoaderList
);
334 StoreLoaderName(SelectionName
);
335 Status
= StartEFIImageList(DiscoveredPathList
, Entry
->LoadOptions
, TYPE_LEGACY
, L
"legacy loader", 0, &ErrorInStep
, TRUE
, FALSE
);
336 if (Status
== EFI_NOT_FOUND
) {
337 if (ErrorInStep
== 1) {
338 Print(L
"\nPlease make sure that you have the latest firmware update installed.\n");
339 } else if (ErrorInStep
== 3) {
340 Print(L
"\nThe firmware refused to boot from the selected volume. Note that external\n"
341 L
"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
344 FinishExternalScreen();
345 } /* static VOID StartLegacy() */
347 // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
348 VOID
StartLegacyUEFI(LEGACY_ENTRY
*Entry
, CHAR16
*SelectionName
)
350 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (UEFI mode)");
351 StoreLoaderName(SelectionName
);
353 BdsLibConnectDevicePath (Entry
->BdsOption
->DevicePath
);
354 BdsLibDoLegacyBoot(Entry
->BdsOption
);
356 // If we get here, it means that there was a failure....
357 Print(L
"Failure booting legacy (BIOS) OS.");
359 FinishExternalScreen();
360 } // static VOID StartLegacyUEFI()
362 static LEGACY_ENTRY
* AddLegacyEntry(IN CHAR16
*LoaderTitle
, IN REFIT_VOLUME
*Volume
)
364 LEGACY_ENTRY
*Entry
, *SubEntry
;
365 REFIT_MENU_SCREEN
*SubScreen
;
366 CHAR16
*VolDesc
, *LegacyTitle
;
367 CHAR16 ShortcutLetter
= 0;
369 if (LoaderTitle
== NULL
) {
370 if (Volume
->OSName
!= NULL
) {
371 LoaderTitle
= Volume
->OSName
;
372 if (LoaderTitle
[0] == 'W' || LoaderTitle
[0] == 'L')
373 ShortcutLetter
= LoaderTitle
[0];
375 LoaderTitle
= L
"Legacy OS";
377 if (Volume
->VolName
!= NULL
)
378 VolDesc
= Volume
->VolName
;
380 VolDesc
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" : L
"HD";
382 LegacyTitle
= AllocateZeroPool(256 * sizeof(CHAR16
));
383 if (LegacyTitle
!= NULL
)
384 SPrint(LegacyTitle
, 255, L
"Boot %s from %s", LoaderTitle
, VolDesc
);
385 if (IsInSubstring(LegacyTitle
, GlobalConfig
.DontScanVolumes
)) {
386 MyFreePool(LegacyTitle
);
390 // prepare the menu entry
391 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
392 Entry
->me
.Title
= LegacyTitle
;
393 Entry
->me
.Tag
= TAG_LEGACY
;
395 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
396 Entry
->me
.Image
= LoadOSIcon(Volume
->OSIconName
, L
"legacy", FALSE
);
397 Entry
->me
.BadgeImage
= Volume
->VolBadgeImage
;
398 Entry
->Volume
= Volume
;
399 Entry
->LoadOptions
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" :
400 ((Volume
->DiskKind
== DISK_KIND_EXTERNAL
) ? L
"USB" : L
"HD");
401 Entry
->Enabled
= TRUE
;
403 // create the submenu
404 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
405 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
406 SPrint(SubScreen
->Title
, 255, L
"Boot Options for %s on %s", LoaderTitle
, VolDesc
);
407 SubScreen
->TitleImage
= Entry
->me
.Image
;
408 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
409 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
410 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
412 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
416 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
417 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
418 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LoaderTitle
);
419 SubEntry
->me
.Tag
= TAG_LEGACY
;
420 SubEntry
->Volume
= Entry
->Volume
;
421 SubEntry
->LoadOptions
= Entry
->LoadOptions
;
422 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
424 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
425 Entry
->me
.SubScreen
= SubScreen
;
426 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
428 } /* static LEGACY_ENTRY * AddLegacyEntry() */
432 Create a rEFInd boot option from a Legacy BIOS protocol option.
434 static LEGACY_ENTRY
* AddLegacyEntryUEFI(BDS_COMMON_OPTION
*BdsOption
, IN UINT16 DiskType
)
436 LEGACY_ENTRY
*Entry
, *SubEntry
;
437 REFIT_MENU_SCREEN
*SubScreen
;
438 CHAR16 ShortcutLetter
= 0;
439 CHAR16
*LegacyDescription
= StrDuplicate(BdsOption
->Description
);
441 if (IsInSubstring(LegacyDescription
, GlobalConfig
.DontScanVolumes
))
444 // Remove stray spaces, since many EFIs produce descriptions with lots of
445 // extra spaces, especially at the end; this throws off centering of the
446 // description on the screen....
447 LimitStringLength(LegacyDescription
, 100);
449 // prepare the menu entry
450 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
451 Entry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
452 SPrint(Entry
->me
.Title
, 255, L
"Boot legacy target %s", LegacyDescription
);
453 Entry
->me
.Tag
= TAG_LEGACY_UEFI
;
455 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
456 Entry
->me
.Image
= LoadOSIcon(L
"legacy", L
"legacy", TRUE
);
457 Entry
->LoadOptions
= (DiskType
== BBS_CDROM
) ? L
"CD" :
458 ((DiskType
== BBS_USB
) ? L
"USB" : L
"HD");
459 Entry
->me
.BadgeImage
= GetDiskBadge(DiskType
);
460 Entry
->BdsOption
= BdsOption
;
461 Entry
->Enabled
= TRUE
;
463 // create the submenu
464 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
465 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
466 SPrint(SubScreen
->Title
, 255, L
"No boot options for legacy target");
467 SubScreen
->TitleImage
= Entry
->me
.Image
;
468 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
469 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
470 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
472 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
476 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
477 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
478 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LegacyDescription
);
479 SubEntry
->me
.Tag
= TAG_LEGACY_UEFI
;
480 Entry
->BdsOption
= BdsOption
;
481 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
483 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
484 Entry
->me
.SubScreen
= SubScreen
;
485 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
487 } /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
490 Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
491 In testing, protocol has not been implemented on Macs but has been
492 implemented on most UEFI PCs.
493 Restricts output to disks of the specified DiskType.
495 static VOID
ScanLegacyUEFI(IN UINTN DiskType
)
498 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
499 UINT16
*BootOrder
= NULL
;
501 CHAR16 BootOption
[10];
502 UINTN BootOrderSize
= 0;
504 BDS_COMMON_OPTION
*BdsOption
;
506 BBS_BBS_DEVICE_PATH
*BbsDevicePath
= NULL
;
507 BOOLEAN SearchingForUsb
= FALSE
;
509 InitializeListHead (&TempList
);
510 ZeroMem (Buffer
, sizeof (Buffer
));
512 // If LegacyBios protocol is not implemented on this platform, then
513 //we do not support this type of legacy boot on this machine.
514 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
515 if (EFI_ERROR (Status
))
518 // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
519 // so we set DiskType inappropriately elsewhere in the program and
520 // "translate" it here.
521 if (DiskType
== BBS_USB
) {
522 DiskType
= BBS_HARDDISK
;
523 SearchingForUsb
= TRUE
;
526 // Grab the boot order
527 BootOrder
= BdsLibGetVariableAndSize(L
"BootOrder", &gEfiGlobalVariableGuid
, &BootOrderSize
);
528 if (BootOrder
== NULL
) {
533 while (Index
< BootOrderSize
/ sizeof (UINT16
))
535 // Grab each boot option variable from the boot order, and convert
536 // the variable into a BDS boot option
537 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
538 BdsOption
= BdsLibVariableToOption (&TempList
, BootOption
);
540 if (BdsOption
!= NULL
) {
541 BbsDevicePath
= (BBS_BBS_DEVICE_PATH
*)BdsOption
->DevicePath
;
542 // Only add the entry if it is of a requested type (e.g. USB, HD)
543 // Two checks necessary because some systems return EFI boot loaders
544 // with a DeviceType value that would inappropriately include them
545 // as legacy loaders....
546 if ((BbsDevicePath
->DeviceType
== DiskType
) && (BdsOption
->DevicePath
->Type
== DEVICE_TYPE_BIOS
)) {
547 // USB flash drives appear as hard disks with certain media flags set.
548 // Look for this, and if present, pass it on with the (technically
549 // incorrect, but internally useful) BBS_TYPE_USB flag set.
550 if (DiskType
== BBS_HARDDISK
) {
551 if (SearchingForUsb
&& (BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
552 AddLegacyEntryUEFI(BdsOption
, BBS_USB
);
553 } else if (!SearchingForUsb
&& !(BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
554 AddLegacyEntryUEFI(BdsOption
, DiskType
);
557 AddLegacyEntryUEFI(BdsOption
, DiskType
);
560 } // if (BdsOption != NULL)
563 } /* static VOID ScanLegacyUEFI() */
565 static VOID
ScanLegacyVolume(REFIT_VOLUME
*Volume
, UINTN VolumeIndex
) {
567 BOOLEAN ShowVolume
, HideIfOthersFound
;
570 HideIfOthersFound
= FALSE
;
571 if (Volume
->IsAppleLegacy
) {
573 HideIfOthersFound
= TRUE
;
574 } else if (Volume
->HasBootCode
) {
576 if (Volume
->BlockIO
== Volume
->WholeDiskBlockIO
&&
577 Volume
->BlockIOOffset
== 0 &&
578 Volume
->OSName
== NULL
)
579 // this is a whole disk (MBR) entry; hide if we have entries for partitions
580 HideIfOthersFound
= TRUE
;
582 if (HideIfOthersFound
) {
583 // check for other bootable entries on the same disk
584 for (VolumeIndex2
= 0; VolumeIndex2
< VolumesCount
; VolumeIndex2
++) {
585 if (VolumeIndex2
!= VolumeIndex
&& Volumes
[VolumeIndex2
]->HasBootCode
&&
586 Volumes
[VolumeIndex2
]->WholeDiskBlockIO
== Volume
->WholeDiskBlockIO
)
592 AddLegacyEntry(NULL
, Volume
);
593 } // static VOID ScanLegacyVolume()
595 // Scan attached optical discs for legacy (BIOS) boot code
596 // and add anything found to the list....
597 VOID
ScanLegacyDisc(VOID
)
600 REFIT_VOLUME
*Volume
;
602 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
603 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
604 Volume
= Volumes
[VolumeIndex
];
605 if (Volume
->DiskKind
== DISK_KIND_OPTICAL
)
606 ScanLegacyVolume(Volume
, VolumeIndex
);
608 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
609 ScanLegacyUEFI(BBS_CDROM
);
611 } /* VOID ScanLegacyDisc() */
613 // Scan internal hard disks for legacy (BIOS) boot code
614 // and add anything found to the list....
615 VOID
ScanLegacyInternal(VOID
)
618 REFIT_VOLUME
*Volume
;
620 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
621 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
622 Volume
= Volumes
[VolumeIndex
];
623 if (Volume
->DiskKind
== DISK_KIND_INTERNAL
)
624 ScanLegacyVolume(Volume
, VolumeIndex
);
626 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
627 // TODO: This actually picks up USB flash drives, too; try to find
628 // a way to differentiate the two....
629 ScanLegacyUEFI(BBS_HARDDISK
);
631 } /* VOID ScanLegacyInternal() */
633 // Scan external disks for legacy (BIOS) boot code
634 // and add anything found to the list....
635 VOID
ScanLegacyExternal(VOID
)
638 REFIT_VOLUME
*Volume
;
640 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
641 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
642 Volume
= Volumes
[VolumeIndex
];
643 if (Volume
->DiskKind
== DISK_KIND_EXTERNAL
)
644 ScanLegacyVolume(Volume
, VolumeIndex
);
646 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
647 // TODO: This actually doesn't do anything useful; leaving in hopes of
648 // fixing it later....
649 ScanLegacyUEFI(BBS_USB
);
651 } /* VOID ScanLegacyExternal() */
653 // Determine what (if any) type of legacy (BIOS) boot support is available
654 VOID
FindLegacyBootType(VOID
) {
656 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
658 GlobalConfig
.LegacyType
= LEGACY_TYPE_NONE
;
660 // UEFI-style legacy BIOS support is available only with some EFI implementations....
661 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
662 if (!EFI_ERROR (Status
))
663 GlobalConfig
.LegacyType
= LEGACY_TYPE_UEFI
;
665 // Macs have their own system. If the firmware vendor code contains the
666 // string "Apple", assume it's available. Note that this overrides the
667 // UEFI type, and might yield false positives if the vendor string
668 // contains "Apple" as part of something bigger, so this isn't 100%
670 if (StriSubCmp(L
"Apple", ST
->FirmwareVendor
))
671 GlobalConfig
.LegacyType
= LEGACY_TYPE_MAC
;
672 } // VOID FindLegacyBootType
674 // Warn the user if legacy OS scans are enabled but the firmware can't support them....
675 VOID
WarnIfLegacyProblems(VOID
) {
676 BOOLEAN found
= FALSE
;
679 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_NONE
) {
681 if (GlobalConfig
.ScanFor
[i
] == 'h' || GlobalConfig
.ScanFor
[i
] == 'b' || GlobalConfig
.ScanFor
[i
] == 'c' ||
682 GlobalConfig
.ScanFor
[i
] == 'H' || GlobalConfig
.ScanFor
[i
] == 'B' || GlobalConfig
.ScanFor
[i
] == 'C')
685 } while ((i
< NUM_SCAN_OPTIONS
) && (!found
));
688 Print(L
"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
689 Print(L
"(BIOS) boot options; however, this is not possible because your computer lacks\n");
690 Print(L
"the necessary Compatibility Support Module (CSM) support or that support is\n");
691 Print(L
"disabled in your firmware.\n");
694 } // if no legacy support
695 } // VOID WarnIfLegacyProblems()