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 "../EfiLib/BdsHelper.h"
67 #include "../EfiLib/legacy.h"
70 extern REFIT_MENU_ENTRY MenuEntryReturn
;
71 extern REFIT_MENU_SCREEN MainMenu
;
73 #ifndef __MAKEWITH_GNUEFI
74 #define LibLocateHandle gBS->LocateHandleBuffer
75 #define DevicePathProtocol gEfiDevicePathProtocolGuid
78 static EFI_STATUS
ActivateMbrPartition(IN EFI_BLOCK_IO
*BlockIO
, IN UINTN PartitionIndex
)
81 UINT8 SectorBuffer
[512];
82 MBR_PARTITION_INFO
*MbrTable
, *EMbrTable
;
83 UINT32 ExtBase
, ExtCurrent
, NextExtCurrent
;
84 UINTN LogicalPartitionIndex
= 4;
89 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
90 if (EFI_ERROR(Status
))
92 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
93 return EFI_NOT_FOUND
; // safety measure #1
95 // add boot code if necessary
97 for (i
= 0; i
< MBR_BOOTCODE_SIZE
; i
++) {
98 if (SectorBuffer
[i
] != 0) {
104 // no boot code found in the MBR, add the syslinux MBR code
105 SetMem(SectorBuffer
, MBR_BOOTCODE_SIZE
, 0);
106 CopyMem(SectorBuffer
, syslinux_mbr
, SYSLINUX_MBR_SIZE
);
109 // set the partition active
110 MbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
112 for (i
= 0; i
< 4; i
++) {
113 if (MbrTable
[i
].Flags
!= 0x00 && MbrTable
[i
].Flags
!= 0x80)
114 return EFI_NOT_FOUND
; // safety measure #2
115 if (i
== PartitionIndex
)
116 MbrTable
[i
].Flags
= 0x80;
117 else if (PartitionIndex
>= 4 && IS_EXTENDED_PART_TYPE(MbrTable
[i
].Type
)) {
118 MbrTable
[i
].Flags
= 0x80;
119 ExtBase
= MbrTable
[i
].StartLBA
;
121 MbrTable
[i
].Flags
= 0x00;
125 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, 0, 512, SectorBuffer
);
126 if (EFI_ERROR(Status
))
129 if (PartitionIndex
>= 4) {
130 // we have to activate a logical partition, so walk the EMBR chain
132 // NOTE: ExtBase was set above while looking at the MBR table
133 for (ExtCurrent
= ExtBase
; ExtCurrent
; ExtCurrent
= NextExtCurrent
) {
135 Status
= refit_call5_wrapper(BlockIO
->ReadBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
136 if (EFI_ERROR(Status
))
138 if (*((UINT16
*)(SectorBuffer
+ 510)) != 0xaa55)
139 return EFI_NOT_FOUND
; // safety measure #3
141 // scan EMBR, set appropriate partition active
142 EMbrTable
= (MBR_PARTITION_INFO
*)(SectorBuffer
+ 446);
144 for (i
= 0; i
< 4; i
++) {
145 if (EMbrTable
[i
].Flags
!= 0x00 && EMbrTable
[i
].Flags
!= 0x80)
146 return EFI_NOT_FOUND
; // safety measure #4
147 if (EMbrTable
[i
].StartLBA
== 0 || EMbrTable
[i
].Size
== 0)
149 if (IS_EXTENDED_PART_TYPE(EMbrTable
[i
].Type
)) {
151 NextExtCurrent
= ExtBase
+ EMbrTable
[i
].StartLBA
;
152 EMbrTable
[i
].Flags
= (PartitionIndex
>= LogicalPartitionIndex
) ? 0x80 : 0x00;
156 EMbrTable
[i
].Flags
= (PartitionIndex
== LogicalPartitionIndex
) ? 0x80 : 0x00;
157 LogicalPartitionIndex
++;
161 // write current EMBR
162 Status
= refit_call5_wrapper(BlockIO
->WriteBlocks
, BlockIO
, BlockIO
->Media
->MediaId
, ExtCurrent
, 512, SectorBuffer
);
163 if (EFI_ERROR(Status
))
166 if (PartitionIndex
< LogicalPartitionIndex
)
167 break; // stop the loop, no need to touch further EMBRs
173 } /* static EFI_STATUS ActivateMbrPartition() */
175 static EFI_GUID AppleVariableVendorID
= { 0x7C436110, 0xAB2A, 0x4BBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82 };
177 static EFI_STATUS
WriteBootDiskHint(IN EFI_DEVICE_PATH
*WholeDiskDevicePath
)
181 Status
= refit_call5_wrapper(RT
->SetVariable
, L
"BootCampHD", &AppleVariableVendorID
,
182 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
183 GetDevicePathSize(WholeDiskDevicePath
), WholeDiskDevicePath
);
184 if (EFI_ERROR(Status
))
191 // firmware device path discovery
194 static UINT8 LegacyLoaderMediaPathData
[] = {
195 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
196 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
197 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
199 static EFI_DEVICE_PATH
*LegacyLoaderMediaPath
= (EFI_DEVICE_PATH
*)LegacyLoaderMediaPathData
;
201 static VOID
ExtractLegacyLoaderPaths(EFI_DEVICE_PATH
**PathList
, UINTN MaxPaths
, EFI_DEVICE_PATH
**HardcodedPathList
)
204 UINTN HandleCount
= 0;
205 UINTN HandleIndex
, HardcodedIndex
;
210 EFI_LOADED_IMAGE
*LoadedImage
;
211 EFI_DEVICE_PATH
*DevicePath
;
214 MaxPaths
--; // leave space for the terminating NULL pointer
216 // get all LoadedImage handles
217 Status
= LibLocateHandle(ByProtocol
, &LoadedImageProtocol
, NULL
, &HandleCount
, &Handles
);
218 if (CheckError(Status
, L
"while listing LoadedImage handles")) {
219 if (HardcodedPathList
) {
220 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
221 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
223 PathList
[PathCount
] = NULL
;
226 for (HandleIndex
= 0; HandleIndex
< HandleCount
&& PathCount
< MaxPaths
; HandleIndex
++) {
227 Handle
= Handles
[HandleIndex
];
229 Status
= refit_call3_wrapper(BS
->HandleProtocol
, Handle
, &LoadedImageProtocol
, (VOID
**) &LoadedImage
);
230 if (EFI_ERROR(Status
))
231 continue; // This can only happen if the firmware scewed up, ignore it.
233 Status
= refit_call3_wrapper(BS
->HandleProtocol
, LoadedImage
->DeviceHandle
, &DevicePathProtocol
, (VOID
**) &DevicePath
);
234 if (EFI_ERROR(Status
))
235 continue; // This happens, ignore it.
237 // Only grab memory range nodes
238 if (DevicePathType(DevicePath
) != HARDWARE_DEVICE_PATH
|| DevicePathSubType(DevicePath
) != HW_MEMMAP_DP
)
241 // Check if we have this device path in the list already
242 // WARNING: This assumes the first node in the device path is unique!
244 for (PathIndex
= 0; PathIndex
< PathCount
; PathIndex
++) {
245 if (DevicePathNodeLength(DevicePath
) != DevicePathNodeLength(PathList
[PathIndex
]))
247 if (CompareMem(DevicePath
, PathList
[PathIndex
], DevicePathNodeLength(DevicePath
)) == 0) {
255 PathList
[PathCount
++] = AppendDevicePath(DevicePath
, LegacyLoaderMediaPath
);
259 if (HardcodedPathList
) {
260 for (HardcodedIndex
= 0; HardcodedPathList
[HardcodedIndex
] && PathCount
< MaxPaths
; HardcodedIndex
++)
261 PathList
[PathCount
++] = HardcodedPathList
[HardcodedIndex
];
263 PathList
[PathCount
] = NULL
;
264 } /* VOID ExtractLegacyLoaderPaths() */
266 // early 2006 Core Duo / Core Solo models
267 static UINT8 LegacyLoaderDevicePath1Data
[] = {
268 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
270 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
271 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
272 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
273 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
275 // mid-2006 Mac Pro (and probably other Core 2 models)
276 static UINT8 LegacyLoaderDevicePath2Data
[] = {
277 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
278 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
279 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
280 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
281 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
282 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
284 // mid-2007 MBP ("Santa Rosa" based models)
285 static UINT8 LegacyLoaderDevicePath3Data
[] = {
286 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
287 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
288 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
289 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
290 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
291 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
294 static UINT8 LegacyLoaderDevicePath4Data
[] = {
295 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
297 0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
298 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
299 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
300 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
302 // late-2008 MB/MBP (NVidia chipset)
303 static UINT8 LegacyLoaderDevicePath5Data
[] = {
304 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
305 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00,
306 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
307 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
308 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
309 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
312 static EFI_DEVICE_PATH
*LegacyLoaderList
[] = {
313 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath1Data
,
314 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath2Data
,
315 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath3Data
,
316 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath4Data
,
317 (EFI_DEVICE_PATH
*)LegacyLoaderDevicePath5Data
,
321 #define MAX_DISCOVERED_PATHS (16)
323 VOID
StartLegacy(IN LEGACY_ENTRY
*Entry
, IN CHAR16
*SelectionName
)
326 EG_IMAGE
*BootLogoImage
;
327 UINTN ErrorInStep
= 0;
328 EFI_DEVICE_PATH
*DiscoveredPathList
[MAX_DISCOVERED_PATHS
];
330 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (Mac mode)");
332 BootLogoImage
= LoadOSIcon(Entry
->Volume
->OSIconName
, L
"legacy", TRUE
);
333 if (BootLogoImage
!= NULL
)
334 BltImageAlpha(BootLogoImage
,
335 (UGAWidth
- BootLogoImage
->Width
) >> 1,
336 (UGAHeight
- BootLogoImage
->Height
) >> 1,
337 &StdBackgroundPixel
);
339 if (Entry
->Volume
->IsMbrPartition
)
340 ActivateMbrPartition(Entry
->Volume
->WholeDiskBlockIO
, Entry
->Volume
->MbrPartitionIndex
);
342 if (Entry
->Volume
->DiskKind
!= DISK_KIND_OPTICAL
&& Entry
->Volume
->WholeDiskDevicePath
!= NULL
)
343 WriteBootDiskHint(Entry
->Volume
->WholeDiskDevicePath
);
345 ExtractLegacyLoaderPaths(DiscoveredPathList
, MAX_DISCOVERED_PATHS
, LegacyLoaderList
);
347 StoreLoaderName(SelectionName
);
348 Status
= StartEFIImageList(DiscoveredPathList
, Entry
->LoadOptions
, TYPE_LEGACY
, L
"legacy loader", 0, &ErrorInStep
, TRUE
, FALSE
);
349 if (Status
== EFI_NOT_FOUND
) {
350 if (ErrorInStep
== 1) {
351 Print(L
"\nPlease make sure that you have the latest firmware update installed.\n");
352 } else if (ErrorInStep
== 3) {
353 Print(L
"\nThe firmware refused to boot from the selected volume. Note that external\n"
354 L
"hard drives are not well-supported by Apple's firmware for legacy OS booting.\n");
357 FinishExternalScreen();
358 } /* static VOID StartLegacy() */
360 // Start a device on a non-Mac using the EFI_LEGACY_BIOS_PROTOCOL
361 VOID
StartLegacyUEFI(LEGACY_ENTRY
*Entry
, CHAR16
*SelectionName
)
363 BeginExternalScreen(TRUE
, L
"Booting Legacy OS (UEFI mode)");
364 StoreLoaderName(SelectionName
);
366 BdsLibConnectDevicePath (Entry
->BdsOption
->DevicePath
);
367 BdsLibDoLegacyBoot(Entry
->BdsOption
);
369 // If we get here, it means that there was a failure....
370 Print(L
"Failure booting legacy (BIOS) OS.");
372 FinishExternalScreen();
373 } // static VOID StartLegacyUEFI()
375 static LEGACY_ENTRY
* AddLegacyEntry(IN CHAR16
*LoaderTitle
, IN REFIT_VOLUME
*Volume
)
377 LEGACY_ENTRY
*Entry
, *SubEntry
;
378 REFIT_MENU_SCREEN
*SubScreen
;
379 CHAR16
*VolDesc
, *LegacyTitle
;
380 CHAR16 ShortcutLetter
= 0;
382 if (LoaderTitle
== NULL
) {
383 if (Volume
->OSName
!= NULL
) {
384 LoaderTitle
= Volume
->OSName
;
385 if (LoaderTitle
[0] == 'W' || LoaderTitle
[0] == 'L')
386 ShortcutLetter
= LoaderTitle
[0];
388 LoaderTitle
= L
"Legacy OS";
390 if (Volume
->VolName
!= NULL
)
391 VolDesc
= Volume
->VolName
;
393 VolDesc
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" : L
"HD";
395 LegacyTitle
= AllocateZeroPool(256 * sizeof(CHAR16
));
396 if (LegacyTitle
!= NULL
)
397 SPrint(LegacyTitle
, 255, L
"Boot %s from %s", LoaderTitle
, VolDesc
);
398 if (IsInSubstring(LegacyTitle
, GlobalConfig
.DontScanVolumes
)) {
399 MyFreePool(LegacyTitle
);
403 // prepare the menu entry
404 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
405 Entry
->me
.Title
= LegacyTitle
;
406 Entry
->me
.Tag
= TAG_LEGACY
;
408 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
409 Entry
->me
.Image
= LoadOSIcon(Volume
->OSIconName
, L
"legacy", FALSE
);
410 Entry
->me
.BadgeImage
= Volume
->VolBadgeImage
;
411 Entry
->Volume
= Volume
;
412 Entry
->LoadOptions
= (Volume
->DiskKind
== DISK_KIND_OPTICAL
) ? L
"CD" :
413 ((Volume
->DiskKind
== DISK_KIND_EXTERNAL
) ? L
"USB" : L
"HD");
414 Entry
->Enabled
= TRUE
;
416 // create the submenu
417 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
418 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
419 SPrint(SubScreen
->Title
, 255, L
"Boot Options for %s on %s", LoaderTitle
, VolDesc
);
420 SubScreen
->TitleImage
= Entry
->me
.Image
;
421 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
422 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
423 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
425 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
429 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
430 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
431 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LoaderTitle
);
432 SubEntry
->me
.Tag
= TAG_LEGACY
;
433 SubEntry
->Volume
= Entry
->Volume
;
434 SubEntry
->LoadOptions
= Entry
->LoadOptions
;
435 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
437 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
438 Entry
->me
.SubScreen
= SubScreen
;
439 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
441 } /* static LEGACY_ENTRY * AddLegacyEntry() */
445 Create a rEFInd boot option from a Legacy BIOS protocol option.
447 static LEGACY_ENTRY
* AddLegacyEntryUEFI(BDS_COMMON_OPTION
*BdsOption
, IN UINT16 DiskType
)
449 LEGACY_ENTRY
*Entry
, *SubEntry
;
450 REFIT_MENU_SCREEN
*SubScreen
;
451 CHAR16 ShortcutLetter
= 0;
452 CHAR16
*LegacyDescription
= StrDuplicate(BdsOption
->Description
);
454 if (IsInSubstring(LegacyDescription
, GlobalConfig
.DontScanVolumes
))
457 // Remove stray spaces, since many EFIs produce descriptions with lots of
458 // extra spaces, especially at the end; this throws off centering of the
459 // description on the screen....
460 LimitStringLength(LegacyDescription
, 100);
462 // prepare the menu entry
463 Entry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
464 Entry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
465 SPrint(Entry
->me
.Title
, 255, L
"Boot legacy target %s", LegacyDescription
);
466 Entry
->me
.Tag
= TAG_LEGACY_UEFI
;
468 Entry
->me
.ShortcutLetter
= ShortcutLetter
;
469 Entry
->me
.Image
= LoadOSIcon(L
"legacy", L
"legacy", TRUE
);
470 Entry
->LoadOptions
= (DiskType
== BBS_CDROM
) ? L
"CD" :
471 ((DiskType
== BBS_USB
) ? L
"USB" : L
"HD");
472 Entry
->me
.BadgeImage
= GetDiskBadge(DiskType
);
473 Entry
->BdsOption
= BdsOption
;
474 Entry
->Enabled
= TRUE
;
476 // create the submenu
477 SubScreen
= AllocateZeroPool(sizeof(REFIT_MENU_SCREEN
));
478 SubScreen
->Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
479 SPrint(SubScreen
->Title
, 255, L
"No boot options for legacy target");
480 SubScreen
->TitleImage
= Entry
->me
.Image
;
481 SubScreen
->Hint1
= StrDuplicate(SUBSCREEN_HINT1
);
482 if (GlobalConfig
.HideUIFlags
& HIDEUI_FLAG_EDITOR
) {
483 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2_NO_EDITOR
);
485 SubScreen
->Hint2
= StrDuplicate(SUBSCREEN_HINT2
);
489 SubEntry
= AllocateZeroPool(sizeof(LEGACY_ENTRY
));
490 SubEntry
->me
.Title
= AllocateZeroPool(256 * sizeof(CHAR16
));
491 SPrint(SubEntry
->me
.Title
, 255, L
"Boot %s", LegacyDescription
);
492 SubEntry
->me
.Tag
= TAG_LEGACY_UEFI
;
493 Entry
->BdsOption
= BdsOption
;
494 AddMenuEntry(SubScreen
, (REFIT_MENU_ENTRY
*)SubEntry
);
496 AddMenuEntry(SubScreen
, &MenuEntryReturn
);
497 Entry
->me
.SubScreen
= SubScreen
;
498 AddMenuEntry(&MainMenu
, (REFIT_MENU_ENTRY
*)Entry
);
500 } /* static LEGACY_ENTRY * AddLegacyEntryUEFI() */
503 Scan for legacy BIOS targets on machines that implement EFI_LEGACY_BIOS_PROTOCOL.
504 In testing, protocol has not been implemented on Macs but has been
505 implemented on most UEFI PCs.
506 Restricts output to disks of the specified DiskType.
508 static VOID
ScanLegacyUEFI(IN UINTN DiskType
)
511 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
512 UINT16
*BootOrder
= NULL
;
514 CHAR16 BootOption
[10];
515 UINTN BootOrderSize
= 0;
517 BDS_COMMON_OPTION
*BdsOption
;
519 BBS_BBS_DEVICE_PATH
*BbsDevicePath
= NULL
;
520 BOOLEAN SearchingForUsb
= FALSE
;
522 InitializeListHead (&TempList
);
523 ZeroMem (Buffer
, sizeof (Buffer
));
525 // If LegacyBios protocol is not implemented on this platform, then
526 //we do not support this type of legacy boot on this machine.
527 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
528 if (EFI_ERROR (Status
))
531 // EFI calls USB drives BBS_HARDDRIVE, but we want to distinguish them,
532 // so we set DiskType inappropriately elsewhere in the program and
533 // "translate" it here.
534 if (DiskType
== BBS_USB
) {
535 DiskType
= BBS_HARDDISK
;
536 SearchingForUsb
= TRUE
;
539 // Grab the boot order
540 BootOrder
= BdsLibGetVariableAndSize(L
"BootOrder", &gEfiGlobalVariableGuid
, &BootOrderSize
);
541 if (BootOrder
== NULL
) {
546 while (Index
< BootOrderSize
/ sizeof (UINT16
))
548 // Grab each boot option variable from the boot order, and convert
549 // the variable into a BDS boot option
550 UnicodeSPrint (BootOption
, sizeof (BootOption
), L
"Boot%04x", BootOrder
[Index
]);
551 BdsOption
= BdsLibVariableToOption (&TempList
, BootOption
);
553 if (BdsOption
!= NULL
) {
554 BbsDevicePath
= (BBS_BBS_DEVICE_PATH
*)BdsOption
->DevicePath
;
555 // Only add the entry if it is of a requested type (e.g. USB, HD)
556 // Two checks necessary because some systems return EFI boot loaders
557 // with a DeviceType value that would inappropriately include them
558 // as legacy loaders....
559 if ((BbsDevicePath
->DeviceType
== DiskType
) && (BdsOption
->DevicePath
->Type
== DEVICE_TYPE_BIOS
)) {
560 // USB flash drives appear as hard disks with certain media flags set.
561 // Look for this, and if present, pass it on with the (technically
562 // incorrect, but internally useful) BBS_TYPE_USB flag set.
563 if (DiskType
== BBS_HARDDISK
) {
564 if (SearchingForUsb
&& (BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
565 AddLegacyEntryUEFI(BdsOption
, BBS_USB
);
566 } else if (!SearchingForUsb
&& !(BbsDevicePath
->StatusFlag
& (BBS_MEDIA_PRESENT
| BBS_MEDIA_MAYBE_PRESENT
))) {
567 AddLegacyEntryUEFI(BdsOption
, DiskType
);
570 AddLegacyEntryUEFI(BdsOption
, DiskType
);
573 } // if (BdsOption != NULL)
576 } /* static VOID ScanLegacyUEFI() */
578 static VOID
ScanLegacyVolume(REFIT_VOLUME
*Volume
, UINTN VolumeIndex
) {
580 BOOLEAN ShowVolume
, HideIfOthersFound
;
583 HideIfOthersFound
= FALSE
;
584 if (Volume
->IsAppleLegacy
) {
586 HideIfOthersFound
= TRUE
;
587 } else if (Volume
->HasBootCode
) {
589 if (Volume
->BlockIO
== Volume
->WholeDiskBlockIO
&&
590 Volume
->BlockIOOffset
== 0 &&
591 Volume
->OSName
== NULL
)
592 // this is a whole disk (MBR) entry; hide if we have entries for partitions
593 HideIfOthersFound
= TRUE
;
595 if (HideIfOthersFound
) {
596 // check for other bootable entries on the same disk
597 for (VolumeIndex2
= 0; VolumeIndex2
< VolumesCount
; VolumeIndex2
++) {
598 if (VolumeIndex2
!= VolumeIndex
&& Volumes
[VolumeIndex2
]->HasBootCode
&&
599 Volumes
[VolumeIndex2
]->WholeDiskBlockIO
== Volume
->WholeDiskBlockIO
)
605 AddLegacyEntry(NULL
, Volume
);
606 } // static VOID ScanLegacyVolume()
608 // Scan attached optical discs for legacy (BIOS) boot code
609 // and add anything found to the list....
610 VOID
ScanLegacyDisc(VOID
)
613 REFIT_VOLUME
*Volume
;
615 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
616 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
617 Volume
= Volumes
[VolumeIndex
];
618 if (Volume
->DiskKind
== DISK_KIND_OPTICAL
)
619 ScanLegacyVolume(Volume
, VolumeIndex
);
621 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
622 ScanLegacyUEFI(BBS_CDROM
);
624 } /* VOID ScanLegacyDisc() */
626 // Scan internal hard disks for legacy (BIOS) boot code
627 // and add anything found to the list....
628 VOID
ScanLegacyInternal(VOID
)
631 REFIT_VOLUME
*Volume
;
633 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
634 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
635 Volume
= Volumes
[VolumeIndex
];
636 if (Volume
->DiskKind
== DISK_KIND_INTERNAL
)
637 ScanLegacyVolume(Volume
, VolumeIndex
);
639 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
640 // TODO: This actually picks up USB flash drives, too; try to find
641 // a way to differentiate the two....
642 ScanLegacyUEFI(BBS_HARDDISK
);
644 } /* VOID ScanLegacyInternal() */
646 // Scan external disks for legacy (BIOS) boot code
647 // and add anything found to the list....
648 VOID
ScanLegacyExternal(VOID
)
651 REFIT_VOLUME
*Volume
;
653 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_MAC
) {
654 for (VolumeIndex
= 0; VolumeIndex
< VolumesCount
; VolumeIndex
++) {
655 Volume
= Volumes
[VolumeIndex
];
656 if (Volume
->DiskKind
== DISK_KIND_EXTERNAL
)
657 ScanLegacyVolume(Volume
, VolumeIndex
);
659 } else if (GlobalConfig
.LegacyType
== LEGACY_TYPE_UEFI
) {
660 // TODO: This actually doesn't do anything useful; leaving in hopes of
661 // fixing it later....
662 ScanLegacyUEFI(BBS_USB
);
664 } /* VOID ScanLegacyExternal() */
666 // Determine what (if any) type of legacy (BIOS) boot support is available
667 VOID
FindLegacyBootType(VOID
) {
669 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
671 GlobalConfig
.LegacyType
= LEGACY_TYPE_NONE
;
673 // UEFI-style legacy BIOS support is available only with some EFI implementations....
674 Status
= refit_call3_wrapper(gBS
->LocateProtocol
, &gEfiLegacyBootProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
675 if (!EFI_ERROR (Status
))
676 GlobalConfig
.LegacyType
= LEGACY_TYPE_UEFI
;
678 // Macs have their own system. If the firmware vendor code contains the
679 // string "Apple", assume it's available. Note that this overrides the
680 // UEFI type, and might yield false positives if the vendor string
681 // contains "Apple" as part of something bigger, so this isn't 100%
683 if (StriSubCmp(L
"Apple", ST
->FirmwareVendor
))
684 GlobalConfig
.LegacyType
= LEGACY_TYPE_MAC
;
685 } // VOID FindLegacyBootType
687 // Warn the user if legacy OS scans are enabled but the firmware can't support them....
688 VOID
WarnIfLegacyProblems(VOID
) {
689 BOOLEAN found
= FALSE
;
692 if (GlobalConfig
.LegacyType
== LEGACY_TYPE_NONE
) {
694 if (GlobalConfig
.ScanFor
[i
] == 'h' || GlobalConfig
.ScanFor
[i
] == 'b' || GlobalConfig
.ScanFor
[i
] == 'c' ||
695 GlobalConfig
.ScanFor
[i
] == 'H' || GlobalConfig
.ScanFor
[i
] == 'B' || GlobalConfig
.ScanFor
[i
] == 'C')
698 } while ((i
< NUM_SCAN_OPTIONS
) && (!found
));
701 Print(L
"NOTE: refind.conf's 'scanfor' line specifies scanning for one or more legacy\n");
702 Print(L
"(BIOS) boot options; however, this is not possible because your computer lacks\n");
703 Print(L
"the necessary Compatibility Support Module (CSM) support or that support is\n");
704 Print(L
"disabled in your firmware.\n");
707 } // if no legacy support
708 } // VOID WarnIfLegacyProblems()