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), or (at your option) any later version.
44 * This program is free software: you can redistribute it and/or modify
45 * it under the terms of the GNU General Public License as published by
46 * the Free Software Foundation, either version 3 of the License, or
47 * (at your option) any later version.
49 * This program is distributed in the hope that it will be useful,
50 * but WITHOUT ANY WARRANTY; without even the implied warranty of
51 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52 * GNU General Public License for more details.
54 * You should have received a copy of the GNU General Public License
55 * along with this program. If not, see <http://www.gnu.org/licenses/>.
63 #include "refit_call_wrapper.h"
65 #include "syslinux_mbr.h"
66 #include "mystrings.h"
67 #include "../EfiLib/BdsHelper.h"
68 #include "../EfiLib/legacy.h"
71 extern REFIT_MENU_ENTRY MenuEntryReturn
;
72 extern REFIT_MENU_SCREEN MainMenu
;
74 #ifndef __MAKEWITH_GNUEFI
75 #define LibLocateHandle gBS->LocateHandleBuffer
76 #define DevicePathProtocol gEfiDevicePathProtocolGuid
79 static EFI_STATUS
ActivateMbrPartition(IN EFI_BLOCK_IO
*BlockIO
, IN UINTN PartitionIndex
)
82 UINT8 SectorBuffer
[512];
83 MBR_PARTITION_INFO
*MbrTable
, *EMbrTable
;
84 UINT32 ExtBase
, ExtCurrent
, NextExtCurrent
;
85 UINTN LogicalPartitionIndex
= 4;
90 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
91 if (EFI_ERROR(Status
))
93 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
94 return EFI_NOT_FOUND
; // safety measure #1
96 // add boot code if necessary
98 for (i
= 0; i
< MBR_BOOTCODE_SIZE
; i
++) {
99 if (SectorBuffer
[i
] != 0) {
105 // no boot code found in the MBR, add the syslinux MBR code
106 SetMem(SectorBuffer
, MBR_BOOTCODE_SIZE
, 0);
107 CopyMem(SectorBuffer
, syslinux_mbr
, SYSLINUX_MBR_SIZE
);
110 // set the partition active
111 MbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
113 for (i
= 0; i
< 4; i
++) {
114 if (MbrTable
[i
].Flags
!= 0x00 && MbrTable
[i
].Flags
!= 0x80)
115 return EFI_NOT_FOUND
; // safety measure #2
116 if (i
== PartitionIndex
)
117 MbrTable
[i
].Flags
= 0x80;
118 else if (PartitionIndex
>= 4 && IS_EXTENDED_PART_TYPE(MbrTable
[i
].Type
)) {
119 MbrTable
[i
].Flags
= 0x80;
120 ExtBase
= MbrTable
[i
].StartLBA
;
122 MbrTable
[i
].Flags
= 0x00;
126 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
127 if (EFI_ERROR(Status
))
130 if (PartitionIndex
>= 4) {
131 // we have to activate a logical partition, so walk the EMBR chain
133 // NOTE: ExtBase was set above while looking at the MBR table
134 for (ExtCurrent
= ExtBase
; ExtCurrent
; ExtCurrent
= NextExtCurrent
) {
136 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
137 if (EFI_ERROR(Status
))
139 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
140 return EFI_NOT_FOUND
; // safety measure #3
142 // scan EMBR, set appropriate partition active
143 EMbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
145 for (i
= 0; i
< 4; i
++) {
146 if (EMbrTable
[i
].Flags
!= 0x00 && EMbrTable
[i
].Flags
!= 0x80)
147 return EFI_NOT_FOUND
; // safety measure #4
148 if (EMbrTable
[i
].StartLBA
== 0 || EMbrTable
[i
].Size
== 0)
150 if (IS_EXTENDED_PART_TYPE(EMbrTable
[i
].Type
)) {
152 NextExtCurrent
= ExtBase
+ EMbrTable
[i
].StartLBA
;
153 EMbrTable
[i
].Flags
= (PartitionIndex
>= LogicalPartitionIndex
) ? 0x80 : 0x00;
157 EMbrTable
[i
].Flags
= (PartitionIndex
== LogicalPartitionIndex
) ? 0x80 : 0x00;
158 LogicalPartitionIndex
++;
162 // write current EMBR
163 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
164 if (EFI_ERROR(Status
))
167 if (PartitionIndex
< LogicalPartitionIndex
)
168 break; // stop the loop, no need to touch further EMBRs
174 } /* static EFI_STATUS ActivateMbrPartition() */
176 static EFI_GUID AppleVariableVendorID
= { 0x7C436110, 0xAB2A, 0x4BBB, { 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 } };
178 static EFI_STATUS
WriteBootDiskHint(IN EFI_DEVICE_PATH
*WholeDiskDevicePath
)
182 Status
= refit_call5_wrapper(RT
->SetVariable
, L
"BootCampHD", &AppleVariableVendorID
,
183 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
184 GetDevicePathSize(WholeDiskDevicePath
), WholeDiskDevicePath
);
185 if (EFI_ERROR(Status
))
192 // firmware device path discovery
195 static UINT8 LegacyLoaderMediaPathData
[] = {
196 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
197 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
198 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
200 static EFI_DEVICE_PATH
*LegacyLoaderMediaPath
= (EFI_DEVICE_PATH
*)LegacyLoaderMediaPathData
;
202 static VOID
ExtractLegacyLoaderPaths(EFI_DEVICE_PATH
**PathList
, UINTN MaxPaths
, EFI_DEVICE_PATH
**HardcodedPathList
)
205 UINTN HandleCount
= 0;
206 UINTN HandleIndex
, HardcodedIndex
;
211 EFI_LOADED_IMAGE
*LoadedImage
;
212 EFI_DEVICE_PATH
*DevicePath
;
215 MaxPaths
--; // leave space for the terminating NULL pointer
217 // get all LoadedImage handles
218 Status
= LibLocateHandle(ByProtocol
, &LoadedImageProtocol
, NULL
, &HandleCount
, &Handles
);
219 if (CheckError(Status
, L
"while listing LoadedImage handles")) {
220 if (HardcodedPathList
) {
221 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
222 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
224 PathList
[PathCount
] = NULL
;
227 for (HandleIndex
= 0; HandleIndex
< HandleCount
&& PathCount
< MaxPaths
; HandleIndex
++) {
228 Handle
= Handles
[HandleIndex
];
230 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Handle
, &LoadedImageProtocol
, (VOID
**) &LoadedImage
);
231 if (EFI_ERROR(Status
))
232 continue; // This can only happen if the firmware scewed up, ignore it.
234 Status
= refit_call3_wrapper(BS
->HandleProtocol
, LoadedImage
->DeviceHandle
, &DevicePathProtocol
, (VOID
**) &DevicePath
);
235 if (EFI_ERROR(Status
))
236 continue; // This happens, ignore it.
238 // Only grab memory range nodes
239 if (DevicePathType(DevicePath
) != HARDWARE_DEVICE_PATH
|| DevicePathSubType(DevicePath
) != HW_MEMMAP_DP
)
242 // Check if we have this device path in the list already
243 // WARNING: This assumes the first node in the device path is unique!
245 for (PathIndex
= 0; PathIndex
< PathCount
; PathIndex
++) {
246 if (DevicePathNodeLength(DevicePath
) != DevicePathNodeLength(PathList
[PathIndex
]))
248 if (CompareMem(DevicePath
, PathList
[PathIndex
], DevicePathNodeLength(DevicePath
)) == 0) {
256 PathList
[PathCount
++] = AppendDevicePath(DevicePath
, LegacyLoaderMediaPath
);
260 if (HardcodedPathList
) {
261 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
262 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
264 PathList
[PathCount
] = NULL
;
265 } /* VOID ExtractLegacyLoaderPaths() */
267 // early 2006 Core Duo / Core Solo models
268 static UINT8 LegacyLoaderDevicePath1Data
[] = {
269 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
271 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
272 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
273 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
274 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
276 // mid-2006 Mac Pro (and probably other Core 2 models)
277 static UINT8 LegacyLoaderDevicePath2Data
[] = {
278 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
280 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
281 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
282 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
283 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
285 // mid-2007 MBP ("Santa Rosa" based models)
286 static UINT8 LegacyLoaderDevicePath3Data
[] = {
287 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
288 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
289 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
290 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
291 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
292 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
295 static UINT8 LegacyLoaderDevicePath4Data
[] = {
296 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
298 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
299 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
300 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
301 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
303 // late-2008 MB/MBP (NVidia chipset)
304 static UINT8 LegacyLoaderDevicePath5Data
[] = {
305 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
306 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
307 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
308 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
309 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
310 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
313 static EFI_DEVICE_PATH
*LegacyLoaderList
[] = {
314 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath1Data
,
315 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath2Data
,
316 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath3Data
,
317 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath4Data
,
318 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath5Data
,
322 #define MAX_DISCOVERED_PATHS (16)
324 VOID
StartLegacy(IN LEGACY_ENTRY
*Entry
, IN CHAR16
*SelectionName
)
327 EG_IMAGE
*BootLogoImage
;
328 UINTN ErrorInStep
= 0;
329 EFI_DEVICE_PATH
*DiscoveredPathList
[MAX_DISCOVERED_PATHS
];
331 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (Mac mode)");
333 BootLogoImage
= LoadOSIcon(Entry
->Volume
->OSIconName
, L
"legacy", TRUE
);
334 if (BootLogoImage
!= NULL
)
335 BltImageAlpha(BootLogoImage
,
336 (UGAWidth
- BootLogoImage
->Width
) >> 1,
337 (UGAHeight
- BootLogoImage
->Height
) >> 1,
338 &StdBackgroundPixel
);
340 if (Entry
->Volume
->IsMbrPartition
)
341 ActivateMbrPartition(Entry
->Volume
->WholeDiskBlockIO
, Entry
->Volume
->MbrPartitionIndex
);
343 if (Entry
->Volume
->DiskKind
!= DISK_KIND_OPTICAL
&& Entry
->Volume
->WholeDiskDevicePath
!= NULL
)
344 WriteBootDiskHint(Entry
->Volume
->WholeDiskDevicePath
);
346 ExtractLegacyLoaderPaths(DiscoveredPathList
, MAX_DISCOVERED_PATHS
, LegacyLoaderList
);
348 StoreLoaderName(SelectionName
);
349 Status
= StartEFIImageList(DiscoveredPathList
, Entry
->LoadOptions
, TYPE_LEGACY
, L
"legacy loader", 0, &ErrorInStep
, TRUE
, FALSE
);
350 if (Status
== EFI_NOT_FOUND
) {
351 if (ErrorInStep
== 1) {
352 Print(L
"\nPlease make sure that you have the latest firmware update installed.\n");
353 } else if (ErrorInStep
== 3) {
354 Print(L
"\nThe firmware refused to boot from the selected volume. Note that external\n"
355 L
"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
358 FinishExternalScreen();
359 } /* static VOID StartLegacy() */
361 // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
362 VOID
StartLegacyUEFI(LEGACY_ENTRY
*Entry
, CHAR16
*SelectionName
)
364 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (UEFI mode)");
365 StoreLoaderName(SelectionName
);
367 BdsLibConnectDevicePath (Entry
->BdsOption
->DevicePath
);
368 BdsLibDoLegacyBoot(Entry
->BdsOption
);
370 // If we get here, it means that there was a failure....
371 Print(L
"Failure booting legacy (BIOS) OS.");
373 FinishExternalScreen();
374 } // static VOID StartLegacyUEFI()
376 static LEGACY_ENTRY
* AddLegacyEntry(IN CHAR16
*LoaderTitle
, IN REFIT_VOLUME
*Volume
)
378 LEGACY_ENTRY
*Entry
, *SubEntry
;
379 REFIT_MENU_SCREEN
*SubScreen
;
380 CHAR16
*VolDesc
, *LegacyTitle
;
381 CHAR16 ShortcutLetter
= 0;
383 if (LoaderTitle
== NULL
) {
384 if (Volume
->OSName
!= NULL
) {
385 LoaderTitle
= Volume
->OSName
;
386 if (LoaderTitle
[0] == 'W' || LoaderTitle
[0] == 'L')
387 ShortcutLetter
= LoaderTitle
[0];
389 LoaderTitle
= L
"Legacy OS";
391 if (Volume
->VolName
!= NULL
)
392 VolDesc
= Volume
->VolName
;
394 VolDesc
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" : L
"HD";
396 LegacyTitle
= AllocateZeroPool(256 * sizeof(CHAR16
));
397 if (LegacyTitle
!= NULL
)
398 SPrint(LegacyTitle
, 255, L
"Boot %s from %s", LoaderTitle
, VolDesc
);
399 if (IsInSubstring(LegacyTitle
, GlobalConfig
.DontScanVolumes
)) {
400 MyFreePool(LegacyTitle
);
404 // prepare the menu entry
405 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
406 Entry
->me
.Title
= LegacyTitle
;
407 Entry
->me
.Tag
= TAG_LEGACY
;
409 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
410 Entry
->me
.Image
= LoadOSIcon(Volume
->OSIconName
, L
"legacy", FALSE
);
411 Entry
->me
.BadgeImage
= Volume
->VolBadgeImage
;
412 Entry
->Volume
= Volume
;
413 Entry
->LoadOptions
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" :
414 ((Volume
->DiskKind
== DISK_KIND_EXTERNAL
) ? L
"USB" : L
"HD");
415 Entry
->Enabled
= TRUE
;
417 // create the submenu
418 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
419 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
420 SPrint(SubScreen
->Title
, 255, L
"Boot Options for %s on %s", LoaderTitle
, VolDesc
);
421 SubScreen
->TitleImage
= Entry
->me
.Image
;
422 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
423 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
424 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
426 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
430 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
431 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
432 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LoaderTitle
);
433 SubEntry
->me
.Tag
= TAG_LEGACY
;
434 SubEntry
->Volume
= Entry
->Volume
;
435 SubEntry
->LoadOptions
= Entry
->LoadOptions
;
436 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
438 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
439 Entry
->me
.SubScreen
= SubScreen
;
440 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
442 } /* static LEGACY_ENTRY * AddLegacyEntry() */
446 Create a rEFInd boot option from a Legacy BIOS protocol option.
448 static LEGACY_ENTRY
* AddLegacyEntryUEFI(BDS_COMMON_OPTION
*BdsOption
, IN UINT16 DiskType
)
450 LEGACY_ENTRY
*Entry
, *SubEntry
;
451 REFIT_MENU_SCREEN
*SubScreen
;
452 CHAR16 ShortcutLetter
= 0;
453 CHAR16
*LegacyDescription
= StrDuplicate(BdsOption
->Description
);
455 if (IsInSubstring(LegacyDescription
, GlobalConfig
.DontScanVolumes
))
458 // Remove stray spaces, since many EFIs produce descriptions with lots of
459 // extra spaces, especially at the end; this throws off centering of the
460 // description on the screen....
461 LimitStringLength(LegacyDescription
, 100);
463 // prepare the menu entry
464 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
465 Entry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
466 SPrint(Entry
->me
.Title
, 255, L
"Boot legacy target %s", LegacyDescription
);
467 Entry
->me
.Tag
= TAG_LEGACY_UEFI
;
469 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
470 Entry
->me
.Image
= LoadOSIcon(L
"legacy", L
"legacy", TRUE
);
471 Entry
->LoadOptions
= (DiskType
== BBS_CDROM
) ? L
"CD" :
472 ((DiskType
== BBS_USB
) ? L
"USB" : L
"HD");
473 Entry
->me
.BadgeImage
= GetDiskBadge(DiskType
);
474 Entry
->BdsOption
= BdsOption
;
475 Entry
->Enabled
= TRUE
;
477 // create the submenu
478 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
479 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
480 SPrint(SubScreen
->Title
, 255, L
"No boot options for legacy target");
481 SubScreen
->TitleImage
= Entry
->me
.Image
;
482 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
483 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
484 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
486 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
490 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
491 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
492 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LegacyDescription
);
493 SubEntry
->me
.Tag
= TAG_LEGACY_UEFI
;
494 Entry
->BdsOption
= BdsOption
;
495 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
497 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
498 Entry
->me
.SubScreen
= SubScreen
;
499 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
501 } /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
504 Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
505 In testing, protocol has not been implemented on Macs but has been
506 implemented on most UEFI PCs.
507 Restricts output to disks of the specified DiskType.
509 static VOID
ScanLegacyUEFI(IN UINTN DiskType
)
512 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
513 UINT16
*BootOrder
= NULL
;
515 CHAR16 BootOption
[10];
516 UINTN BootOrderSize
= 0;
518 BDS_COMMON_OPTION
*BdsOption
;
520 BBS_BBS_DEVICE_PATH
*BbsDevicePath
= NULL
;
521 BOOLEAN SearchingForUsb
= FALSE
;
523 InitializeListHead (&TempList
);
524 ZeroMem (Buffer
, sizeof (Buffer
));
526 // If LegacyBios protocol is not implemented on this platform, then
527 //we do not support this type of legacy boot on this machine.
528 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
529 if (EFI_ERROR (Status
))
532 // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
533 // so we set DiskType inappropriately elsewhere in the program and
534 // "translate" it here.
535 if (DiskType
== BBS_USB
) {
536 DiskType
= BBS_HARDDISK
;
537 SearchingForUsb
= TRUE
;
540 // Grab the boot order
541 BootOrder
= BdsLibGetVariableAndSize(L
"BootOrder", &gEfiGlobalVariableGuid
, &BootOrderSize
);
542 if (BootOrder
== NULL
) {
547 while (Index
< BootOrderSize
/ sizeof (UINT16
))
549 // Grab each boot option variable from the boot order, and convert
550 // the variable into a BDS boot option
551 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
552 BdsOption
= BdsLibVariableToOption (&TempList
, BootOption
);
554 if (BdsOption
!= NULL
) {
555 BbsDevicePath
= (BBS_BBS_DEVICE_PATH
*)BdsOption
->DevicePath
;
556 // Only add the entry if it is of a requested type (e.g. USB, HD)
557 // Two checks necessary because some systems return EFI boot loaders
558 // with a DeviceType value that would inappropriately include them
559 // as legacy loaders....
560 if ((BbsDevicePath
->DeviceType
== DiskType
) && (BdsOption
->DevicePath
->Type
== DEVICE_TYPE_BIOS
)) {
561 // USB flash drives appear as hard disks with certain media flags set.
562 // Look for this, and if present, pass it on with the (technically
563 // incorrect, but internally useful) BBS_TYPE_USB flag set.
564 if (DiskType
== BBS_HARDDISK
) {
565 if (SearchingForUsb
&& (BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
566 AddLegacyEntryUEFI(BdsOption
, BBS_USB
);
567 } else if (!SearchingForUsb
&& !(BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
568 AddLegacyEntryUEFI(BdsOption
, DiskType
);
571 AddLegacyEntryUEFI(BdsOption
, DiskType
);
574 } // if (BdsOption != NULL)
577 } /* static VOID ScanLegacyUEFI() */
579 static VOID
ScanLegacyVolume(REFIT_VOLUME
*Volume
, UINTN VolumeIndex
) {
581 BOOLEAN ShowVolume
, HideIfOthersFound
;
584 HideIfOthersFound
= FALSE
;
585 if (Volume
->IsAppleLegacy
) {
587 HideIfOthersFound
= TRUE
;
588 } else if (Volume
->HasBootCode
) {
590 if (Volume
->BlockIO
== Volume
->WholeDiskBlockIO
&&
591 Volume
->BlockIOOffset
== 0 &&
592 Volume
->OSName
== NULL
)
593 // this is a whole disk (MBR) entry; hide if we have entries for partitions
594 HideIfOthersFound
= TRUE
;
596 if (HideIfOthersFound
) {
597 // check for other bootable entries on the same disk
598 for (VolumeIndex2
= 0; VolumeIndex2
< VolumesCount
; VolumeIndex2
++) {
599 if (VolumeIndex2
!= VolumeIndex
&& Volumes
[VolumeIndex2
]->HasBootCode
&&
600 Volumes
[VolumeIndex2
]->WholeDiskBlockIO
== Volume
->WholeDiskBlockIO
)
606 AddLegacyEntry(NULL
, Volume
);
607 } // static VOID ScanLegacyVolume()
609 // Scan attached optical discs for legacy (BIOS) boot code
610 // and add anything found to the list....
611 VOID
ScanLegacyDisc(VOID
)
614 REFIT_VOLUME
*Volume
;
616 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
617 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
618 Volume
= Volumes
[VolumeIndex
];
619 if (Volume
->DiskKind
== DISK_KIND_OPTICAL
)
620 ScanLegacyVolume(Volume
, VolumeIndex
);
622 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
623 ScanLegacyUEFI(BBS_CDROM
);
625 } /* VOID ScanLegacyDisc() */
627 // Scan internal hard disks for legacy (BIOS) boot code
628 // and add anything found to the list....
629 VOID
ScanLegacyInternal(VOID
)
632 REFIT_VOLUME
*Volume
;
634 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
635 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
636 Volume
= Volumes
[VolumeIndex
];
637 if (Volume
->DiskKind
== DISK_KIND_INTERNAL
)
638 ScanLegacyVolume(Volume
, VolumeIndex
);
640 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
641 // TODO: This actually picks up USB flash drives, too; try to find
642 // a way to differentiate the two....
643 ScanLegacyUEFI(BBS_HARDDISK
);
645 } /* VOID ScanLegacyInternal() */
647 // Scan external disks for legacy (BIOS) boot code
648 // and add anything found to the list....
649 VOID
ScanLegacyExternal(VOID
)
652 REFIT_VOLUME
*Volume
;
654 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
655 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
656 Volume
= Volumes
[VolumeIndex
];
657 if (Volume
->DiskKind
== DISK_KIND_EXTERNAL
)
658 ScanLegacyVolume(Volume
, VolumeIndex
);
660 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
661 // TODO: This actually doesn't do anything useful; leaving in hopes of
662 // fixing it later....
663 ScanLegacyUEFI(BBS_USB
);
665 } /* VOID ScanLegacyExternal() */
667 // Determine what (if any) type of legacy (BIOS) boot support is available
668 VOID
FindLegacyBootType(VOID
) {
670 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
672 GlobalConfig
.LegacyType
= LEGACY_TYPE_NONE
;
674 // UEFI-style legacy BIOS support is available only with some EFI implementations....
675 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
676 if (!EFI_ERROR (Status
))
677 GlobalConfig
.LegacyType
= LEGACY_TYPE_UEFI
;
679 // Macs have their own system. If the firmware vendor code contains the
680 // string "Apple", assume it's available. Note that this overrides the
681 // UEFI type, and might yield false positives if the vendor string
682 // contains "Apple" as part of something bigger, so this isn't 100%
684 if (StriSubCmp(L
"Apple", ST
->FirmwareVendor
))
685 GlobalConfig
.LegacyType
= LEGACY_TYPE_MAC
;
686 } // VOID FindLegacyBootType
688 // Warn the user if legacy OS scans are enabled but the firmware can't support them....
689 VOID
WarnIfLegacyProblems(VOID
) {
690 BOOLEAN found
= FALSE
;
693 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_NONE
) {
695 if (GlobalConfig
.ScanFor
[i
] == 'h' || GlobalConfig
.ScanFor
[i
] == 'b' || GlobalConfig
.ScanFor
[i
] == 'c' ||
696 GlobalConfig
.ScanFor
[i
] == 'H' || GlobalConfig
.ScanFor
[i
] == 'B' || GlobalConfig
.ScanFor
[i
] == 'C')
699 } while ((i
< NUM_SCAN_OPTIONS
) && (!found
));
702 Print(L
"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
703 Print(L
"(BIOS) boot options; however, this is not possible because your computer lacks\n");
704 Print(L
"the necessary Compatibility Support Module (CSM) support or that support is\n");
705 Print(L
"disabled in your firmware.\n");
708 } // if no legacy support
709 } // VOID WarnIfLegacyProblems()