VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxGenericBdsLib/BdsBoot.c@ 37146

Last change on this file since 37146 was 37146, checked in by vboxsync, 14 years ago

EFI: order.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.7 KB
Line 
1/* $Id: BdsBoot.c 37146 2011-05-19 02:41:02Z vboxsync $ */
2/** @file
3 * BdsBoot.c
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19
20This code is based on:
21
22BDS Lib functions which relate with create or process the boot option.
23
24Copyright (c) 2004 - 2009, Intel Corporation. <BR>
25All rights reserved. This program and the accompanying materials
26are licensed and made available under the terms and conditions of the BSD License
27which accompanies this distribution. The full text of the license may be found at
28http://opensource.org/licenses/bsd-license.php
29
30THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
31WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
32
33*/
34
35#include "InternalBdsLib.h"
36
37BOOLEAN mEnumBootDevice = FALSE;
38
39///
40/// This GUID is used for an EFI Variable that stores the front device paths
41/// for a partial device path that starts with the HD node.
42///
43EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
44
45
46
47/**
48 Boot the legacy system with the boot option
49
50 @param Option The legacy boot option which have BBS device path
51
52 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
53 legacy boot.
54 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
55
56**/
57EFI_STATUS
58BdsLibDoLegacyBoot (
59 IN BDS_COMMON_OPTION *Option
60 )
61{
62 EFI_STATUS Status;
63 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
64
65 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
66 if (EFI_ERROR (Status)) {
67 //
68 // If no LegacyBios protocol we do not support legacy boot
69 //
70 return EFI_UNSUPPORTED;
71 }
72 //
73 // Notes: if we separate the int 19, then we don't need to refresh BBS
74 //
75 BdsRefreshBbsTableForBoot (Option);
76
77 //
78 // Write boot to OS performance data for legacy boot.
79 //
80 PERF_CODE (
81 WriteBootToOsPerformanceData ();
82 );
83
84 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
85 return LegacyBios->LegacyBoot (
86 LegacyBios,
87 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
88 Option->LoadOptionsSize,
89 Option->LoadOptions
90 );
91}
92
93/**
94 Internal function to check if the input boot option is a valid EFI NV Boot####.
95
96 @param OptionToCheck Boot option to be checked.
97
98 @retval TRUE This boot option matches a valid EFI NV Boot####.
99 @retval FALSE If not.
100
101**/
102BOOLEAN
103IsBootOptionValidNVVarialbe (
104 IN BDS_COMMON_OPTION *OptionToCheck
105 )
106{
107 LIST_ENTRY TempList;
108 BDS_COMMON_OPTION *BootOption;
109 BOOLEAN Valid;
110 CHAR16 OptionName[20];
111
112 Valid = FALSE;
113
114 InitializeListHead (&TempList);
115 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
116
117 BootOption = BdsLibVariableToOption (&TempList, OptionName);
118 if (BootOption == NULL) {
119 return FALSE;
120 }
121
122 //
123 // If the Boot Option Number and Device Path matches, OptionToCheck matches a
124 // valid EFI NV Boot####.
125 //
126 if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
127 (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
128 {
129 Valid = TRUE;
130 }
131
132 FreePool (BootOption);
133
134 return Valid;
135}
136/**
137 Process the boot option follow the UEFI specification and
138 special treat the legacy boot option with BBS_DEVICE_PATH.
139
140 @param Option The boot option need to be processed
141 @param DevicePath The device path which describe where to load the
142 boot image or the legacy BBS device path to boot
143 the legacy OS
144 @param ExitDataSize The size of exit data.
145 @param ExitData Data returned when Boot image failed.
146
147 @retval EFI_SUCCESS Boot from the input boot option successfully.
148 @retval EFI_NOT_FOUND If the Device Path is not found in the system
149
150**/
151EFI_STATUS
152EFIAPI
153BdsLibBootViaBootOption (
154 IN BDS_COMMON_OPTION *Option,
155 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
156 OUT UINTN *ExitDataSize,
157 OUT CHAR16 **ExitData OPTIONAL
158 )
159{
160 EFI_STATUS Status;
161 EFI_HANDLE Handle;
162 EFI_HANDLE ImageHandle;
163 EFI_DEVICE_PATH_PROTOCOL *FilePath;
164 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
165 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
166 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
167 LIST_ENTRY TempBootLists;
168 EFI_SECURITY_ARCH_PROTOCOL *SecurityProtocol;
169 CHAR16 *NewFileName;
170 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToTxt;
171
172 //
173 // Record the performance data for End of BDS
174 //
175 PERF_END(NULL, "BDS", NULL, 0);
176
177 *ExitDataSize = 0;
178 *ExitData = NULL;
179
180 //
181 // Notes: put EFI64 ROM Shadow Solution
182 //
183 EFI64_SHADOW_ALL_LEGACY_ROM ();
184
185 //
186 // Notes: this code can be remove after the s3 script table
187 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
188 // EVT_SIGNAL_LEGACY_BOOT
189 //
190 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
191 if (!EFI_ERROR (Status)) {
192 AcpiS3Save->S3Save (AcpiS3Save, NULL);
193 }
194 //
195 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
196 // full device path
197 //
198 WorkingDevicePath = NULL;
199 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
200 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
201 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
202 (HARDDRIVE_DEVICE_PATH *)DevicePath
203 );
204 if (WorkingDevicePath != NULL) {
205 DevicePath = WorkingDevicePath;
206 }
207 }
208 //
209 // Signal the EVT_SIGNAL_READY_TO_BOOT event
210 //
211 EfiSignalEventReadyToBoot();
212
213
214 //
215 // Set Boot Current
216 //
217 if (IsBootOptionValidNVVarialbe (Option)) {
218 //
219 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
220 // In this case, "BootCurrent" is not created.
221 // Only create the BootCurrent variable when it points to a valid Boot#### variable.
222 //
223 DEBUG((DEBUG_INFO, "Boot: Current\n"));
224 gRT->SetVariable (
225 L"BootCurrent",
226 &gEfiGlobalVariableGuid,
227 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
228 sizeof (UINT16),
229 &Option->BootCurrent
230 );
231 }
232
233 ASSERT (Option->DevicePath != NULL);
234 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
235 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
236 ) {
237 //
238 // Check to see if we should legacy BOOT. If yes then do the legacy boot
239 //
240 return BdsLibDoLegacyBoot (Option);
241 }
242
243 //
244 // If the boot option points to Internal FV shell, make sure it is valid
245 //
246 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
247 if (!EFI_ERROR(Status)) {
248 if (Option->DevicePath != NULL) {
249 FreePool(Option->DevicePath);
250 }
251 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
252 ASSERT(Option->DevicePath != NULL);
253 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
254 //
255 // Update the shell boot option
256 //
257 InitializeListHead (&TempBootLists);
258 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
259
260 //
261 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
262 //
263 FreePool (DevicePath);
264 DevicePath = Option->DevicePath;
265 }
266
267 //
268 // Measure GPT Table by SAP protocol.
269 //
270 Status = gBS->LocateProtocol (
271 &gEfiSecurityArchProtocolGuid,
272 NULL,
273 (VOID**) &SecurityProtocol
274 );
275 if (!EFI_ERROR (Status)) {
276 Status = SecurityProtocol->FileAuthenticationState (SecurityProtocol, 0, DevicePath);
277 }
278
279 DEBUG_CODE_BEGIN();
280 UINTN DevicePathTypeValue;
281 CHAR16 *HiiString;
282 CHAR16 *BootStringNumber;
283 UINTN BufferSize;
284
285 DevicePathTypeValue = BdsGetBootTypeFromDevicePath (Option->DevicePath);
286
287 //
288 // store number string of boot option temporary.
289 //
290 HiiString = NULL;
291 switch (DevicePathTypeValue) {
292 case BDS_EFI_ACPI_FLOPPY_BOOT:
293 HiiString = L"EFI Floppy";
294 break;
295 case BDS_EFI_MEDIA_CDROM_BOOT:
296 case BDS_EFI_MESSAGE_SATA_BOOT:
297 case BDS_EFI_MESSAGE_ATAPI_BOOT:
298 HiiString = L"EFI DVD/CDROM";
299 break;
300 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
301 HiiString = L"EFI USB Device";
302 break;
303 case BDS_EFI_MESSAGE_SCSI_BOOT:
304 HiiString = L"EFI SCSI Device";
305 break;
306 case BDS_EFI_MESSAGE_MISC_BOOT:
307 HiiString = L"EFI Misc Device";
308 break;
309 case BDS_EFI_MESSAGE_MAC_BOOT:
310 HiiString = L"EFI Network";
311 break;
312 case BBS_DEVICE_PATH:
313 //
314 // Do nothing for legacy boot option.
315 //
316 break;
317 default:
318 DEBUG((EFI_D_INFO, "Can not find HiiString for given device path type 0x%x\n", DevicePathTypeValue));
319 }
320
321 //
322 // If found Hii description string then cat Hii string with original description.
323 //
324 if (HiiString != NULL) {
325 BootStringNumber = Option->Description;
326 BufferSize = StrSize(BootStringNumber);
327 BufferSize += StrSize(HiiString);
328 Option->Description = AllocateZeroPool(BufferSize);
329 StrCpy (Option->Description, HiiString);
330 if (StrnCmp (BootStringNumber, L"0", 1) != 0) {
331 StrCat (Option->Description, L" ");
332 StrCat (Option->Description, BootStringNumber);
333 }
334
335 FreePool (BootStringNumber);
336 }
337
338 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
339
340 DEBUG_CODE_END();
341 if (DevPathToTxt == NULL)
342 {
343 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevPathToTxt);
344 ASSERT((!EFI_ERROR(Status)));
345 }
346
347 Status = gBS->LoadImage (
348 TRUE,
349 mBdsImageHandle,
350 DevicePath,
351 NULL,
352 0,
353 &ImageHandle
354 );
355
356 DEBUG((DEBUG_INFO, "%a:%d LoadingImage '%s' - %r\n", __FILE__, __LINE__, DevPathToTxt->ConvertDevicePathToText(DevicePath, TRUE, FALSE), Status));
357 //
358 // If we didn't find an image directly, we need to try as if it is a removable device boot option
359 // and load the image according to the default boot behavior for removable device.
360 //
361 if (EFI_ERROR (Status)) {
362 //
363 // check if there is a bootable removable media could be found in this device path ,
364 // and get the bootable media handle
365 //
366 Handle = BdsLibGetBootableHandle(DevicePath, &NewFileName);
367 if (Handle == NULL) {
368 goto Done;
369 }
370 //
371 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
372 // machinename is ia32, ia64, x64, ...
373 //
374 FilePath = FileDevicePath (Handle, NewFileName);
375 if (FilePath != NULL) {
376 DEBUG((DEBUG_INFO, "%a:%d LoadingImage FilePath:'%s'\n", __FILE__, __LINE__, DevPathToTxt->ConvertDevicePathToText(FilePath, TRUE, FALSE)));
377 Status = gBS->LoadImage (
378 TRUE,
379 mBdsImageHandle,
380 FilePath,
381 NULL,
382 0,
383 &ImageHandle
384 );
385 if (EFI_ERROR (Status)) {
386 //
387 // The DevicePath failed, and it's not a valid
388 // removable media device.
389 //
390 goto Done;
391 }
392 }
393 }
394
395 if (EFI_ERROR (Status)) {
396 //
397 // It there is any error from the Boot attempt exit now.
398 //
399 goto Done;
400 }
401 //
402 // Provide the image with it's load options
403 //
404 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
405 ASSERT_EFI_ERROR (Status);
406
407 if (Option->LoadOptionsSize != 0) {
408 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
409 ImageInfo->LoadOptions = Option->LoadOptions;
410 }
411 //
412 // Before calling the image, enable the Watchdog Timer for
413 // the 5 Minute period
414 //
415#ifndef VBOX
416 /* Some special guests don't return here */
417 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
418#endif
419
420 //
421 // Write boot to OS performance data for UEFI boot
422 //
423 PERF_CODE (
424 WriteBootToOsPerformanceData ();
425 );
426
427 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
428 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
429
430 //
431 // Clear the Watchdog Timer after the image returns
432 //
433#ifndef VBOX
434 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
435#endif
436
437Done:
438 //
439 // Clear Boot Current
440 //
441 gRT->SetVariable (
442 L"BootCurrent",
443 &gEfiGlobalVariableGuid,
444 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
445 0,
446 &Option->BootCurrent
447 );
448
449 return Status;
450}
451
452
453/**
454 Expand a device path that starts with a hard drive media device path node to be a
455 full device path that includes the full hardware path to the device. We need
456 to do this so it can be booted. As an optimization the front match (the part point
457 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
458 so a connect all is not required on every boot. All successful history device path
459 which point to partition node (the front part) will be saved.
460
461 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
462 drive media device path.
463 @return A Pointer to the full device path or NULL if a valid Hard Drive device path
464 cannot be found.
465
466**/
467EFI_DEVICE_PATH_PROTOCOL *
468EFIAPI
469BdsExpandPartitionPartialDevicePathToFull (
470 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
471 )
472{
473 EFI_STATUS Status;
474 UINTN BlockIoHandleCount;
475 EFI_HANDLE *BlockIoBuffer;
476 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
477 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
478 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
479 UINTN Index;
480 UINTN InstanceNum;
481 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
482 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
483 UINTN CachedDevicePathSize;
484 BOOLEAN DeviceExist;
485 BOOLEAN NeedAdjust;
486 EFI_DEVICE_PATH_PROTOCOL *Instance;
487 UINTN Size;
488
489 FullDevicePath = NULL;
490 //
491 // Check if there is prestore 'HDDP' variable.
492 // If exist, search the front path which point to partition node in the variable instants.
493 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
494 //
495 CachedDevicePath = BdsLibGetVariableAndSize (
496 L"HDDP",
497 &mHdBootVariablePrivateGuid,
498 &CachedDevicePathSize
499 );
500
501 if (CachedDevicePath != NULL) {
502 TempNewDevicePath = CachedDevicePath;
503 DeviceExist = FALSE;
504 NeedAdjust = FALSE;
505 do {
506 //
507 // Check every instance of the variable
508 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
509 // partial partition boot option. Second, check whether the instance could be connected.
510 //
511 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
512 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
513 //
514 // Connect the device path instance, the device path point to hard drive media device path node
515 // e.g. ACPI() /PCI()/ATA()/Partition()
516 //
517 Status = BdsLibConnectDevicePath (Instance);
518 if (!EFI_ERROR (Status)) {
519 DeviceExist = TRUE;
520 break;
521 }
522 }
523 //
524 // Come here means the first instance is not matched
525 //
526 NeedAdjust = TRUE;
527 FreePool(Instance);
528 } while (TempNewDevicePath != NULL);
529
530 if (DeviceExist) {
531 //
532 // Find the matched device path.
533 // Append the file path information from the boot option and return the fully expanded device path.
534 //
535 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
536 FullDevicePath = AppendDevicePath (Instance, DevicePath);
537
538 //
539 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
540 //
541 if (NeedAdjust) {
542 //
543 // First delete the matched instance.
544 //
545 TempNewDevicePath = CachedDevicePath;
546 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
547 FreePool (TempNewDevicePath);
548
549 //
550 // Second, append the remaining path after the matched instance
551 //
552 TempNewDevicePath = CachedDevicePath;
553 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
554 FreePool (TempNewDevicePath);
555 //
556 // Save the matching Device Path so we don't need to do a connect all next time
557 //
558 Status = gRT->SetVariable (
559 L"HDDP",
560 &mHdBootVariablePrivateGuid,
561 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
562 GetDevicePathSize (CachedDevicePath),
563 CachedDevicePath
564 );
565 }
566
567 FreePool (Instance);
568 FreePool (CachedDevicePath);
569 return FullDevicePath;
570 }
571 }
572
573 //
574 // If we get here we fail to find or 'HDDP' not exist, and now we need
575 // to search all devices in the system for a matched partition
576 //
577 BdsLibConnectAllDriversToAllControllers ();
578 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
579 if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
580 //
581 // If there was an error or there are no device handles that support
582 // the BLOCK_IO Protocol, then return.
583 //
584 return NULL;
585 }
586 //
587 // Loop through all the device handles that support the BLOCK_IO Protocol
588 //
589 for (Index = 0; Index < BlockIoHandleCount; Index++) {
590
591 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
592 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
593 continue;
594 }
595
596 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
597 //
598 // Find the matched partition device path
599 //
600 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
601 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
602
603 //
604 // Save the matched partition device path in 'HDDP' variable
605 //
606 if (CachedDevicePath != NULL) {
607 //
608 // Save the matched partition device path as first instance of 'HDDP' variable
609 //
610 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
611 TempNewDevicePath = CachedDevicePath;
612 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
613 FreePool(TempNewDevicePath);
614
615 TempNewDevicePath = CachedDevicePath;
616 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
617 FreePool(TempNewDevicePath);
618 } else {
619 TempNewDevicePath = CachedDevicePath;
620 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
621 FreePool(TempNewDevicePath);
622 }
623 //
624 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
625 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
626 //
627 InstanceNum = 0;
628 ASSERT (CachedDevicePath != NULL);
629 TempNewDevicePath = CachedDevicePath;
630 while (!IsDevicePathEnd (TempNewDevicePath)) {
631 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
632 //
633 // Parse one instance
634 //
635 while (!IsDevicePathEndType (TempNewDevicePath)) {
636 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
637 }
638 InstanceNum++;
639 //
640 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
641 //
642 if (InstanceNum >= 12) {
643 SetDevicePathEndNode (TempNewDevicePath);
644 break;
645 }
646 }
647 } else {
648 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
649 }
650
651 //
652 // Save the matching Device Path so we don't need to do a connect all next time
653 //
654 Status = gRT->SetVariable (
655 L"HDDP",
656 &mHdBootVariablePrivateGuid,
657 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
658 GetDevicePathSize (CachedDevicePath),
659 CachedDevicePath
660 );
661
662 break;
663 }
664 }
665
666 FreePool (CachedDevicePath);
667 if (BlockIoBuffer != NULL) {
668 FreePool (BlockIoBuffer);
669 }
670 return FullDevicePath;
671}
672
673/**
674 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
675 instances, has the same partition node with HardDriveDevicePath device path
676
677 @param BlockIoDevicePath Multi device path instances which need to check
678 @param HardDriveDevicePath A device path which starts with a hard drive media
679 device path.
680
681 @retval TRUE There is a matched device path instance.
682 @retval FALSE There is no matched device path instance.
683
684**/
685BOOLEAN
686EFIAPI
687MatchPartitionDevicePathNode (
688 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
689 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
690 )
691{
692 HARDDRIVE_DEVICE_PATH *TmpHdPath;
693 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
694 BOOLEAN Match;
695 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
696
697 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
698 return FALSE;
699 }
700
701 //
702 // Make PreviousDevicePath == the device path node before the end node
703 //
704 DevicePath = BlockIoDevicePath;
705 BlockIoHdDevicePathNode = NULL;
706
707 //
708 // find the partition device path node
709 //
710 while (!IsDevicePathEnd (DevicePath)) {
711 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
712 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
713 ) {
714 BlockIoHdDevicePathNode = DevicePath;
715 break;
716 }
717
718 DevicePath = NextDevicePathNode (DevicePath);
719 }
720
721 if (BlockIoHdDevicePathNode == NULL) {
722 return FALSE;
723 }
724 //
725 // See if the harddrive device path in blockio matches the orig Hard Drive Node
726 //
727 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
728 Match = FALSE;
729
730 //
731 // Check for the match
732 //
733 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
734 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
735 switch (TmpHdPath->SignatureType) {
736 case SIGNATURE_TYPE_GUID:
737 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
738 break;
739 case SIGNATURE_TYPE_MBR:
740 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
741 break;
742 default:
743 Match = FALSE;
744 break;
745 }
746 }
747
748 return Match;
749}
750
751/**
752 Delete the boot option associated with the handle passed in.
753
754 @param Handle The handle which present the device path to create
755 boot option
756
757 @retval EFI_SUCCESS Delete the boot option success
758 @retval EFI_NOT_FOUND If the Device Path is not found in the system
759 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
760 @retval Other Error return value from SetVariable()
761
762**/
763EFI_STATUS
764BdsLibDeleteOptionFromHandle (
765 IN EFI_HANDLE Handle
766 )
767{
768 UINT16 *BootOrder;
769 UINT8 *BootOptionVar;
770 UINTN BootOrderSize;
771 UINTN BootOptionSize;
772 EFI_STATUS Status;
773 UINTN Index;
774 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
775 UINTN DevicePathSize;
776 UINTN OptionDevicePathSize;
777 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
778 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
779 UINT8 *TempPtr;
780
781 Status = EFI_SUCCESS;
782 BootOrder = NULL;
783 BootOrderSize = 0;
784
785 //
786 // Check "BootOrder" variable, if no, means there is no any boot order.
787 //
788 BootOrder = BdsLibGetVariableAndSize (
789 L"BootOrder",
790 &gEfiGlobalVariableGuid,
791 &BootOrderSize
792 );
793 if (BootOrder == NULL) {
794 return EFI_NOT_FOUND;
795 }
796
797 //
798 // Convert device handle to device path protocol instance
799 //
800 DevicePath = DevicePathFromHandle (Handle);
801 if (DevicePath == NULL) {
802 return EFI_NOT_FOUND;
803 }
804 DevicePathSize = GetDevicePathSize (DevicePath);
805
806 //
807 // Loop all boot order variable and find the matching device path
808 //
809 Index = 0;
810 while (Index < BootOrderSize / sizeof (UINT16)) {
811 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
812 BootOptionVar = BdsLibGetVariableAndSize (
813 BootOption,
814 &gEfiGlobalVariableGuid,
815 &BootOptionSize
816 );
817
818 if (BootOptionVar == NULL) {
819 FreePool (BootOrder);
820 return EFI_OUT_OF_RESOURCES;
821 }
822
823 TempPtr = BootOptionVar;
824 TempPtr += sizeof (UINT32) + sizeof (UINT16);
825 TempPtr += StrSize ((CHAR16 *) TempPtr);
826 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
827 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
828
829 //
830 // Check whether the device path match
831 //
832 if ((OptionDevicePathSize == DevicePathSize) &&
833 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
834 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
835 FreePool (BootOptionVar);
836 break;
837 }
838
839 FreePool (BootOptionVar);
840 Index++;
841 }
842
843 //
844 // Adjust number of boot option for "BootOrder" variable.
845 //
846 Status = gRT->SetVariable (
847 L"BootOrder",
848 &gEfiGlobalVariableGuid,
849 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
850 BootOrderSize,
851 BootOrder
852 );
853
854 FreePool (BootOrder);
855
856 return Status;
857}
858
859
860/**
861 Delete all invalid EFI boot options.
862
863 @retval EFI_SUCCESS Delete all invalid boot option success
864 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
865 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
866 @retval Other Error return value from SetVariable()
867
868**/
869EFI_STATUS
870BdsDeleteAllInvalidEfiBootOption (
871 VOID
872 )
873{
874 UINT16 *BootOrder;
875 UINT8 *BootOptionVar;
876 UINTN BootOrderSize;
877 UINTN BootOptionSize;
878 EFI_STATUS Status;
879 UINTN Index;
880 UINTN Index2;
881 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
882 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
883 UINT8 *TempPtr;
884 CHAR16 *Description;
885
886 Status = EFI_SUCCESS;
887 BootOrder = NULL;
888 BootOrderSize = 0;
889
890 //
891 // Check "BootOrder" variable firstly, this variable hold the number of boot options
892 //
893 BootOrder = BdsLibGetVariableAndSize (
894 L"BootOrder",
895 &gEfiGlobalVariableGuid,
896 &BootOrderSize
897 );
898 if (NULL == BootOrder) {
899 return EFI_NOT_FOUND;
900 }
901
902 Index = 0;
903 while (Index < BootOrderSize / sizeof (UINT16)) {
904 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
905 BootOptionVar = BdsLibGetVariableAndSize (
906 BootOption,
907 &gEfiGlobalVariableGuid,
908 &BootOptionSize
909 );
910 if (NULL == BootOptionVar) {
911 FreePool (BootOrder);
912 return EFI_OUT_OF_RESOURCES;
913 }
914
915 TempPtr = BootOptionVar;
916 TempPtr += sizeof (UINT32) + sizeof (UINT16);
917 Description = (CHAR16 *) TempPtr;
918 TempPtr += StrSize ((CHAR16 *) TempPtr);
919 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
920
921 //
922 // Skip legacy boot option (BBS boot device)
923 //
924 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
925 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
926 FreePool (BootOptionVar);
927 Index++;
928 continue;
929 }
930
931 if (!BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
932 //
933 // Delete this invalid boot option "Boot####"
934 //
935 Status = gRT->SetVariable (
936 BootOption,
937 &gEfiGlobalVariableGuid,
938 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
939 0,
940 NULL
941 );
942 //
943 // Mark this boot option in boot order as deleted
944 //
945 BootOrder[Index] = 0xffff;
946 }
947
948 FreePool (BootOptionVar);
949 Index++;
950 }
951
952 //
953 // Adjust boot order array
954 //
955 Index2 = 0;
956 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
957 if (BootOrder[Index] != 0xffff) {
958 BootOrder[Index2] = BootOrder[Index];
959 Index2 ++;
960 }
961 }
962 Status = gRT->SetVariable (
963 L"BootOrder",
964 &gEfiGlobalVariableGuid,
965 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
966 Index2 * sizeof (UINT16),
967 BootOrder
968 );
969
970 FreePool (BootOrder);
971
972 return Status;
973}
974
975static BOOLEAN bdsCheckFileName(EFI_IMAGE_OPTIONAL_HEADER_UNION *pHdrData, EFI_HANDLE FileSystemHandle, CHAR16 *pu16FileName, CHAR16 **ppNewFileName)
976{
977 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
978 BOOLEAN fNeedDelete = TRUE;
979 CHAR16 *NewFileName;
980 EFI_STATUS Status;
981 Hdr.Union = pHdrData;
982 EFI_IMAGE_DOS_HEADER DosHeader;
983 Status = BdsLibGetImageHeader (
984 FileSystemHandle,
985 pu16FileName,
986 &DosHeader,
987 Hdr,
988 &NewFileName
989 );
990 if (!EFI_ERROR (Status)
991#ifndef VBOX
992 && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
993 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
994#endif
995 ) {
996 fNeedDelete = FALSE;
997 }
998 if (ppNewFileName)
999 *ppNewFileName = NewFileName;
1000 return fNeedDelete;
1001}
1002
1003/**
1004 For EFI boot option, BDS separate them as six types:
1005 1. Network - The boot option points to the SimpleNetworkProtocol device.
1006 Bds will try to automatically create this type boot option when enumerate.
1007 2. Shell - The boot option points to internal flash shell.
1008 Bds will try to automatically create this type boot option when enumerate.
1009 3. Removable BlockIo - The boot option only points to the removable media
1010 device, like USB flash disk, DVD, Floppy etc.
1011 These device should contain a *removable* blockIo
1012 protocol in their device handle.
1013 Bds will try to automatically create this type boot option
1014 when enumerate.
1015 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1016 like HardDisk.
1017 These device should contain a *fixed* blockIo
1018 protocol in their device handle.
1019 BDS will skip fixed blockIo devices, and NOT
1020 automatically create boot option for them. But BDS
1021 will help to delete those fixed blockIo boot option,
1022 whose description rule conflict with other auto-created
1023 boot options.
1024 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
1025 has SimpleFileSystem Protocol, but has no blockio
1026 protocol. These devices do not offer blockIo
1027 protocol, but BDS still can get the
1028 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
1029 Protocol.
1030 6. File - The boot option points to a file. These boot options are usually
1031 created by user manually or OS loader. BDS will not delete or modify
1032 these boot options.
1033
1034 This function will enumerate all possible boot device in the system, and
1035 automatically create boot options for Network, Shell, Removable BlockIo,
1036 and Non-BlockIo Simplefile devices.
1037 It will only execute once of every boot.
1038
1039 @param BdsBootOptionList The header of the link list which indexed all
1040 current boot options
1041
1042 @retval EFI_SUCCESS Finished all the boot device enumerate and create
1043 the boot option base on that boot device
1044
1045 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
1046**/
1047EFI_STATUS
1048EFIAPI
1049BdsLibEnumerateAllBootOption (
1050 IN OUT LIST_ENTRY *BdsBootOptionList
1051 )
1052{
1053 EFI_STATUS Status;
1054 UINT16 FloppyNumber;
1055 UINT16 CdromNumber;
1056 UINT16 UsbNumber;
1057 UINT16 MiscNumber;
1058 UINT16 ScsiNumber;
1059 UINT16 NonBlockNumber;
1060 UINTN NumberBlockIoHandles;
1061 EFI_HANDLE *BlockIoHandles;
1062 EFI_BLOCK_IO_PROTOCOL *BlkIo;
1063 UINTN Index;
1064 UINTN NumberSimpleNetworkHandles;
1065 EFI_HANDLE *SimpleNetworkHandles;
1066 UINTN FvHandleCount;
1067 EFI_HANDLE *FvHandleBuffer;
1068 EFI_FV_FILETYPE Type;
1069 UINTN Size;
1070 EFI_FV_FILE_ATTRIBUTES Attributes;
1071 UINT32 AuthenticationStatus;
1072 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1073 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1074 UINTN DevicePathType;
1075 CHAR16 Buffer[40];
1076 EFI_HANDLE *FileSystemHandles;
1077 UINTN NumberFileSystemHandles;
1078 BOOLEAN NeedDelete;
1079 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1080 //EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1081
1082 FloppyNumber = 0;
1083 CdromNumber = 0;
1084 UsbNumber = 0;
1085 MiscNumber = 0;
1086 ScsiNumber = 0;
1087 ZeroMem (Buffer, sizeof (Buffer));
1088
1089 //
1090 // If the boot device enumerate happened, just get the boot
1091 // device from the boot order variable
1092 //
1093 if (mEnumBootDevice) {
1094 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1095 return Status;
1096 }
1097
1098 //
1099 // Notes: this dirty code is to get the legacy boot option from the
1100 // BBS table and create to variable as the EFI boot option, it should
1101 // be removed after the CSM can provide legacy boot option directly
1102 //
1103 REFRESH_LEGACY_BOOT_OPTIONS;
1104
1105 //
1106 // Delete invalid boot option
1107 //
1108 BdsDeleteAllInvalidEfiBootOption ();
1109
1110 //
1111 // Parse removable media
1112 //
1113 gBS->LocateHandleBuffer (
1114 ByProtocol,
1115 &gEfiBlockIoProtocolGuid,
1116 NULL,
1117 &NumberBlockIoHandles,
1118 &BlockIoHandles
1119 );
1120
1121 for (Index = 0; Index < NumberBlockIoHandles; Index++) {
1122 Status = gBS->HandleProtocol (
1123 BlockIoHandles[Index],
1124 &gEfiBlockIoProtocolGuid,
1125 (VOID **) &BlkIo
1126 );
1127 if (!EFI_ERROR (Status)) {
1128 /* VBOX: For some guests we need to add non-movable devices as boot
1129 * options automatically.
1130 */
1131#ifndef VBOX
1132 if (!BlkIo->Media->RemovableMedia) {
1133 //
1134 // skip the non-removable block devices
1135 //
1136 continue;
1137 }
1138#endif
1139 }
1140 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
1141 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
1142
1143 switch (DevicePathType) {
1144 case BDS_EFI_ACPI_FLOPPY_BOOT:
1145 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", FloppyNumber);
1146 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1147 FloppyNumber++;
1148 break;
1149
1150 //
1151 // Assume a removable SATA device should be the DVD/CD device
1152 //
1153 case BDS_EFI_MESSAGE_ATAPI_BOOT:
1154 case BDS_EFI_MESSAGE_SATA_BOOT:
1155 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", CdromNumber);
1156 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1157 CdromNumber++;
1158 break;
1159
1160 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
1161 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", UsbNumber);
1162 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1163 UsbNumber++;
1164 break;
1165
1166 case BDS_EFI_MESSAGE_SCSI_BOOT:
1167 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", ScsiNumber);
1168 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1169 ScsiNumber++;
1170 break;
1171
1172 case BDS_EFI_MEDIA_HD_BOOT:
1173 case BDS_EFI_MESSAGE_MISC_BOOT:
1174 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", MiscNumber);
1175 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1176 MiscNumber++;
1177 break;
1178
1179 default:
1180 break;
1181 }
1182 }
1183
1184 if (NumberBlockIoHandles != 0) {
1185 FreePool (BlockIoHandles);
1186 }
1187
1188 //
1189 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
1190 //
1191 NonBlockNumber = 0;
1192 gBS->LocateHandleBuffer (
1193 ByProtocol,
1194 &gEfiSimpleFileSystemProtocolGuid,
1195 NULL,
1196 &NumberFileSystemHandles,
1197 &FileSystemHandles
1198 );
1199 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
1200 Status = gBS->HandleProtocol (
1201 FileSystemHandles[Index],
1202 &gEfiBlockIoProtocolGuid,
1203 (VOID **) &BlkIo
1204 );
1205 if (!EFI_ERROR (Status)) {
1206 //
1207 // Skip if the file system handle supports a BlkIo protocol,
1208 //
1209 continue;
1210 }
1211
1212 //
1213 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
1214 // machinename is ia32, ia64, x64, ...
1215 //
1216 //Hdr.Union = &HdrData;
1217 NeedDelete = TRUE;
1218 NeedDelete = bdsCheckFileName(&HdrData, FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME, NULL);
1219 if (NeedDelete)
1220 NeedDelete = bdsCheckFileName(&HdrData, FileSystemHandles[Index], L"\\Mac OS X Install Data\\boot.efi", NULL);
1221 if (NeedDelete)
1222 NeedDelete = bdsCheckFileName(&HdrData, FileSystemHandles[Index], L"\\System\\Library\\CoreServices\\boot.efi", NULL);
1223 if (NeedDelete) {
1224 //
1225 // No such file or the file is not a EFI application, delete this boot option
1226 //
1227 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
1228 } else {
1229 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);
1230 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
1231 NonBlockNumber++;
1232 }
1233 }
1234
1235 if (NumberFileSystemHandles != 0) {
1236 FreePool (FileSystemHandles);
1237 }
1238
1239 //
1240 // Parse Network Boot Device
1241 //
1242 gBS->LocateHandleBuffer (
1243 ByProtocol,
1244 &gEfiSimpleNetworkProtocolGuid,
1245 NULL,
1246 &NumberSimpleNetworkHandles,
1247 &SimpleNetworkHandles
1248 );
1249
1250 for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {
1251 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d", Index);
1252 BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);
1253 }
1254
1255 if (NumberSimpleNetworkHandles != 0) {
1256 FreePool (SimpleNetworkHandles);
1257 }
1258
1259 //
1260 // Check if we have on flash shell
1261 //
1262 gBS->LocateHandleBuffer (
1263 ByProtocol,
1264 &gEfiFirmwareVolume2ProtocolGuid,
1265 NULL,
1266 &FvHandleCount,
1267 &FvHandleBuffer
1268 );
1269 for (Index = 0; Index < FvHandleCount; Index++) {
1270 gBS->HandleProtocol (
1271 FvHandleBuffer[Index],
1272 &gEfiFirmwareVolume2ProtocolGuid,
1273 (VOID **) &Fv
1274 );
1275
1276 Status = Fv->ReadFile (
1277 Fv,
1278 PcdGetPtr(PcdShellFile),
1279 NULL,
1280 &Size,
1281 &Type,
1282 &Attributes,
1283 &AuthenticationStatus
1284 );
1285 if (EFI_ERROR (Status)) {
1286 //
1287 // Skip if no shell file in the FV
1288 //
1289 continue;
1290 }
1291 //
1292 // Build the shell boot option
1293 //
1294 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
1295 }
1296
1297 if (FvHandleCount != 0) {
1298 FreePool (FvHandleBuffer);
1299 }
1300 //
1301 // Make sure every boot only have one time
1302 // boot device enumerate
1303 //
1304 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1305 mEnumBootDevice = TRUE;
1306
1307 return Status;
1308}
1309
1310/**
1311 Build the boot option with the handle parsed in
1312
1313 @param Handle The handle which present the device path to create
1314 boot option
1315 @param BdsBootOptionList The header of the link list which indexed all
1316 current boot options
1317 @param String The description of the boot option.
1318
1319**/
1320VOID
1321EFIAPI
1322BdsLibBuildOptionFromHandle (
1323 IN EFI_HANDLE Handle,
1324 IN LIST_ENTRY *BdsBootOptionList,
1325 IN CHAR16 *String
1326 )
1327{
1328 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1329
1330 DevicePath = DevicePathFromHandle (Handle);
1331
1332 //
1333 // Create and register new boot option
1334 //
1335 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
1336}
1337
1338
1339/**
1340 Build the on flash shell boot option with the handle parsed in.
1341
1342 @param Handle The handle which present the device path to create
1343 on flash shell boot option
1344 @param BdsBootOptionList The header of the link list which indexed all
1345 current boot options
1346
1347**/
1348VOID
1349EFIAPI
1350BdsLibBuildOptionFromShell (
1351 IN EFI_HANDLE Handle,
1352 IN OUT LIST_ENTRY *BdsBootOptionList
1353 )
1354{
1355 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1356 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
1357
1358 DevicePath = DevicePathFromHandle (Handle);
1359
1360 //
1361 // Build the shell device path
1362 //
1363 EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
1364
1365 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
1366
1367 //
1368 // Create and register the shell boot option
1369 //
1370 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
1371
1372}
1373
1374/**
1375 Boot from the UEFI spec defined "BootNext" variable.
1376
1377**/
1378VOID
1379EFIAPI
1380BdsLibBootNext (
1381 VOID
1382 )
1383{
1384 UINT16 *BootNext;
1385 UINTN BootNextSize;
1386 CHAR16 Buffer[20];
1387 BDS_COMMON_OPTION *BootOption;
1388 LIST_ENTRY TempList;
1389 UINTN ExitDataSize;
1390 CHAR16 *ExitData;
1391
1392 //
1393 // Init the boot option name buffer and temp link list
1394 //
1395 InitializeListHead (&TempList);
1396 ZeroMem (Buffer, sizeof (Buffer));
1397
1398 BootNext = BdsLibGetVariableAndSize (
1399 L"BootNext",
1400 &gEfiGlobalVariableGuid,
1401 &BootNextSize
1402 );
1403
1404 //
1405 // Clear the boot next variable first
1406 //
1407 if (BootNext != NULL) {
1408 gRT->SetVariable (
1409 L"BootNext",
1410 &gEfiGlobalVariableGuid,
1411 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1412 0,
1413 BootNext
1414 );
1415
1416 //
1417 // Start to build the boot option and try to boot
1418 //
1419 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
1420 BootOption = BdsLibVariableToOption (&TempList, Buffer);
1421 ASSERT (BootOption != NULL);
1422 BdsLibConnectDevicePath (BootOption->DevicePath);
1423 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
1424 }
1425
1426}
1427
1428/**
1429 Return the bootable media handle.
1430 First, check the device is connected
1431 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1432 Third, detect the the default boot file in the Media, and return the removable Media handle.
1433
1434 @param DevicePath Device Path to a bootable device
1435
1436 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
1437
1438**/
1439EFI_HANDLE
1440EFIAPI
1441BdsLibGetBootableHandle (
1442 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1443 IN OUT CHAR16 **NewFileName
1444 )
1445{
1446 EFI_STATUS Status;
1447 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1448 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
1449 EFI_HANDLE Handle;
1450 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1451 VOID *Buffer;
1452 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1453 UINTN Size;
1454 UINTN TempSize;
1455 EFI_HANDLE ReturnHandle;
1456 EFI_HANDLE *SimpleFileSystemHandles;
1457
1458 UINTN NumberSimpleFileSystemHandles;
1459 UINTN Index;
1460 //EFI_IMAGE_DOS_HEADER DosHeader;
1461 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1462 //EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1463
1464 UpdatedDevicePath = DevicePath;
1465
1466 //
1467 // Check whether the device is connected
1468 //
1469 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
1470 if (EFI_ERROR (Status)) {
1471 //
1472 // Skip the case that the boot option points to a simple file protocol which does not consume block Io protocol,
1473 //
1474 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
1475 if (EFI_ERROR (Status)) {
1476 //
1477 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1478 //
1479 UpdatedDevicePath = DevicePath;
1480 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1481 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1482 }
1483 } else {
1484 //
1485 // Get BlockIo protocol and check removable attribute
1486 //
1487 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1488 //
1489 // Issue a dummy read to the device to check for media change.
1490 // When the removable media is changed, any Block IO read/write will
1491 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1492 // returned. After the Block IO protocol is reinstalled, subsequent
1493 // Block IO read/write will success.
1494 //
1495 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1496 if (Buffer != NULL) {
1497 BlockIo->ReadBlocks (
1498 BlockIo,
1499 BlockIo->Media->MediaId,
1500 0,
1501 BlockIo->Media->BlockSize,
1502 Buffer
1503 );
1504 FreePool(Buffer);
1505 }
1506 }
1507
1508 //
1509 // Detect the the default boot file from removable Media
1510 //
1511
1512 //
1513 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
1514 // Try to locate the USB node device path first, if fail then use its previous PCI node to search
1515 //
1516 DupDevicePath = DuplicateDevicePath (DevicePath);
1517 ASSERT (DupDevicePath != NULL);
1518
1519 UpdatedDevicePath = DupDevicePath;
1520 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1521 //
1522 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
1523 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1524 //
1525 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
1526 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
1527 //
1528 // Remove the usb node, let the device path only point to PCI node
1529 //
1530 SetDevicePathEndNode (UpdatedDevicePath);
1531 UpdatedDevicePath = DupDevicePath;
1532 } else {
1533 UpdatedDevicePath = DevicePath;
1534 }
1535
1536 //
1537 // Get the device path size of boot option
1538 //
1539 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1540 ReturnHandle = NULL;
1541 gBS->LocateHandleBuffer (
1542 ByProtocol,
1543 &gEfiSimpleFileSystemProtocolGuid,
1544 NULL,
1545 &NumberSimpleFileSystemHandles,
1546 &SimpleFileSystemHandles
1547 );
1548 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1549 //
1550 // Get the device path size of SimpleFileSystem handle
1551 //
1552 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1553 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1554 //
1555 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1556 //
1557 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
1558 //
1559 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1560 // machinename is ia32, ia64, x64, ...
1561 //
1562 BOOLEAN fNotFound = bdsCheckFileName(&HdrData, SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME, NewFileName);
1563 if (fNotFound)
1564 fNotFound = bdsCheckFileName(&HdrData, SimpleFileSystemHandles[Index], L"\\Mac OS X Install Data\\boot.efi", NewFileName);
1565 if (fNotFound)
1566 fNotFound = bdsCheckFileName(&HdrData, SimpleFileSystemHandles[Index], L"\\System\\Library\\CoreServices\\boot.efi", NewFileName);
1567 if (!fNotFound)
1568 {
1569 ReturnHandle = SimpleFileSystemHandles[Index];
1570 break;
1571 }
1572 }
1573 }
1574
1575 FreePool(DupDevicePath);
1576
1577 if (SimpleFileSystemHandles != NULL) {
1578 FreePool(SimpleFileSystemHandles);
1579 }
1580
1581 return ReturnHandle;
1582}
1583
1584/**
1585 Check to see if the network cable is plugged in. If the DevicePath is not
1586 connected it will be connected.
1587
1588 @param DevicePath Device Path to check
1589
1590 @retval TRUE DevicePath points to an Network that is connected
1591 @retval FALSE DevicePath does not point to a bootable network
1592
1593**/
1594BOOLEAN
1595BdsLibNetworkBootWithMediaPresent (
1596 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1597 )
1598{
1599 EFI_STATUS Status;
1600 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1601 EFI_HANDLE Handle;
1602 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1603 BOOLEAN MediaPresent;
1604
1605 MediaPresent = FALSE;
1606
1607 UpdatedDevicePath = DevicePath;
1608 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1609 if (EFI_ERROR (Status)) {
1610 //
1611 // Device not present so see if we need to connect it
1612 //
1613 Status = BdsLibConnectDevicePath (DevicePath);
1614 if (!EFI_ERROR (Status)) {
1615 //
1616 // This one should work after we did the connect
1617 //
1618 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1619 }
1620 }
1621
1622 if (!EFI_ERROR (Status)) {
1623 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
1624 if (!EFI_ERROR (Status)) {
1625 if (Snp->Mode->MediaPresentSupported) {
1626 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
1627 //
1628 // In case some one else is using the SNP check to see if it's connected
1629 //
1630 MediaPresent = Snp->Mode->MediaPresent;
1631 } else {
1632 //
1633 // No one is using SNP so we need to Start and Initialize so
1634 // MediaPresent will be valid.
1635 //
1636 Status = Snp->Start (Snp);
1637 if (!EFI_ERROR (Status)) {
1638 Status = Snp->Initialize (Snp, 0, 0);
1639 if (!EFI_ERROR (Status)) {
1640 MediaPresent = Snp->Mode->MediaPresent;
1641 Snp->Shutdown (Snp);
1642 }
1643 Snp->Stop (Snp);
1644 }
1645 }
1646 } else {
1647 MediaPresent = TRUE;
1648 }
1649 }
1650 }
1651
1652 return MediaPresent;
1653}
1654
1655/**
1656 For a bootable Device path, return its boot type.
1657
1658 @param DevicePath The bootable device Path to check
1659
1660 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
1661 which subtype is MEDIA_HARDDRIVE_DP
1662 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
1663 which subtype is MEDIA_CDROM_DP
1664 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
1665 which HID is floppy device.
1666 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
1667 and its last device path node's subtype is MSG_ATAPI_DP.
1668 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
1669 and its last device path node's subtype is MSG_SCSI_DP.
1670 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
1671 and its last device path node's subtype is MSG_USB_DP.
1672 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
1673 its last device path node point to a message device path node.
1674 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
1675 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
1676
1677**/
1678UINT32
1679EFIAPI
1680BdsGetBootTypeFromDevicePath (
1681 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1682 )
1683{
1684 ACPI_HID_DEVICE_PATH *Acpi;
1685 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1686 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1687
1688
1689 if (NULL == DevicePath) {
1690 return BDS_EFI_UNSUPPORT;
1691 }
1692
1693 TempDevicePath = DevicePath;
1694
1695 while (!IsDevicePathEndType (TempDevicePath)) {
1696 switch (DevicePathType (TempDevicePath)) {
1697 case BBS_DEVICE_PATH:
1698 return BDS_LEGACY_BBS_BOOT;
1699 case MEDIA_DEVICE_PATH:
1700 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
1701 return BDS_EFI_MEDIA_HD_BOOT;
1702 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
1703 return BDS_EFI_MEDIA_CDROM_BOOT;
1704 }
1705 break;
1706 case ACPI_DEVICE_PATH:
1707 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
1708 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
1709 return BDS_EFI_ACPI_FLOPPY_BOOT;
1710 }
1711 break;
1712 case MESSAGING_DEVICE_PATH:
1713 //
1714 // Get the last device path node
1715 //
1716 LastDeviceNode = NextDevicePathNode (TempDevicePath);
1717 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
1718 //
1719 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
1720 // skit it
1721 //
1722 LastDeviceNode = NextDevicePathNode (LastDeviceNode);
1723 }
1724 //
1725 // if the device path not only point to driver device, it is not a messaging device path,
1726 //
1727 if (!IsDevicePathEndType (LastDeviceNode)) {
1728 break;
1729 }
1730
1731 if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {
1732 return BDS_EFI_MESSAGE_ATAPI_BOOT;
1733 } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {
1734 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
1735 } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {
1736 return BDS_EFI_MESSAGE_SCSI_BOOT;
1737 } else if (DevicePathSubType(TempDevicePath) == MSG_SATA_DP) {
1738 return BDS_EFI_MESSAGE_SATA_BOOT;
1739 } else if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
1740 return BDS_EFI_MESSAGE_MAC_BOOT;
1741 }
1742 return BDS_EFI_MESSAGE_MISC_BOOT;
1743 default:
1744 break;
1745 }
1746 TempDevicePath = NextDevicePathNode (TempDevicePath);
1747 }
1748
1749 return BDS_EFI_UNSUPPORT;
1750}
1751
1752/**
1753 Check whether the Device path in a boot option points to a valid bootable device,
1754 And if CheckMedia is true, check the device is ready to boot now.
1755
1756 @param DevPath the Device path in a boot option
1757 @param CheckMedia if true, check the device is ready to boot now.
1758
1759 @retval TRUE the Device path is valid
1760 @retval FALSE the Device path is invalid .
1761
1762**/
1763BOOLEAN
1764EFIAPI
1765BdsLibIsValidEFIBootOptDevicePath (
1766 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
1767 IN BOOLEAN CheckMedia
1768 )
1769{
1770 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
1771}
1772
1773/**
1774 Check whether the Device path in a boot option points to a valid bootable device,
1775 And if CheckMedia is true, check the device is ready to boot now.
1776 If Description is not NULL and the device path point to a fixed BlockIo
1777 device, check the description whether conflict with other auto-created
1778 boot options.
1779
1780 @param DevPath the Device path in a boot option
1781 @param CheckMedia if true, check the device is ready to boot now.
1782 @param Description the description in a boot option
1783
1784 @retval TRUE the Device path is valid
1785 @retval FALSE the Device path is invalid .
1786
1787**/
1788BOOLEAN
1789EFIAPI
1790BdsLibIsValidEFIBootOptDevicePathExt (
1791 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
1792 IN BOOLEAN CheckMedia,
1793 IN CHAR16 *Description
1794 )
1795{
1796 EFI_STATUS Status;
1797 EFI_HANDLE Handle;
1798 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1799 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1800 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1801 CHAR16 *NewFileName;
1802
1803 TempDevicePath = DevPath;
1804 LastDeviceNode = DevPath;
1805
1806 //
1807 // Check if it's a valid boot option for network boot device
1808 // Only check if there is SimpleNetworkProtocol installed. If yes, that means
1809 // there is the network card there.
1810 //
1811 Status = gBS->LocateDevicePath (
1812 &gEfiSimpleNetworkProtocolGuid,
1813 &TempDevicePath,
1814 &Handle
1815 );
1816 if (EFI_ERROR (Status)) {
1817 //
1818 // Device not present so see if we need to connect it
1819 //
1820 TempDevicePath = DevPath;
1821 BdsLibConnectDevicePath (TempDevicePath);
1822 Status = gBS->LocateDevicePath (
1823 &gEfiSimpleNetworkProtocolGuid,
1824 &TempDevicePath,
1825 &Handle
1826 );
1827 }
1828
1829 if (!EFI_ERROR (Status)) {
1830 if (CheckMedia) {
1831 //
1832 // Test if it is ready to boot now
1833 //
1834 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
1835 return TRUE;
1836 }
1837 } else {
1838 return TRUE;
1839 }
1840 }
1841
1842 //
1843 // If the boot option points to a file, it is a valid EFI boot option,
1844 // and assume it is ready to boot now
1845 //
1846 while (!IsDevicePathEnd (TempDevicePath)) {
1847 LastDeviceNode = TempDevicePath;
1848 TempDevicePath = NextDevicePathNode (TempDevicePath);
1849 }
1850 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
1851 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
1852 return TRUE;
1853 }
1854
1855 //
1856 // Check if it's a valid boot option for internal Shell
1857 //
1858 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
1859 //
1860 // If the boot option points to Internal FV shell, make sure it is valid
1861 //
1862 TempDevicePath = DevPath;
1863 Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, PcdGetPtr(PcdShellFile));
1864 if (Status == EFI_ALREADY_STARTED) {
1865 return TRUE;
1866 } else {
1867 if (Status == EFI_SUCCESS) {
1868 FreePool (TempDevicePath);
1869 }
1870 return FALSE;
1871 }
1872 }
1873
1874 //
1875 // If the boot option points to a blockIO device:
1876 // if it is a removable blockIo device, it is valid.
1877 // if it is a fixed blockIo device, check its description confliction.
1878 //
1879 TempDevicePath = DevPath;
1880 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1881 if (EFI_ERROR (Status)) {
1882 //
1883 // Device not present so see if we need to connect it
1884 //
1885 Status = BdsLibConnectDevicePath (DevPath);
1886 if (!EFI_ERROR (Status)) {
1887 //
1888 // Try again to get the Block Io protocol after we did the connect
1889 //
1890 TempDevicePath = DevPath;
1891 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1892 }
1893 }
1894
1895 if (!EFI_ERROR (Status)) {
1896 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1897 if (!EFI_ERROR (Status)) {
1898 if (CheckMedia) {
1899 //
1900 // Test if it is ready to boot now
1901 //
1902 if (BdsLibGetBootableHandle (DevPath, &NewFileName) != NULL) {
1903 return TRUE;
1904 }
1905 } else {
1906 return TRUE;
1907 }
1908 }
1909 } else {
1910 //
1911 // if the boot option points to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
1912 //
1913 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1914 if (!EFI_ERROR (Status)) {
1915 if (CheckMedia) {
1916 //
1917 // Test if it is ready to boot now
1918 //
1919 if (BdsLibGetBootableHandle (DevPath, &NewFileName) != NULL) {
1920 return TRUE;
1921 }
1922 } else {
1923 return TRUE;
1924 }
1925 }
1926 }
1927
1928 return FALSE;
1929}
1930
1931
1932/**
1933 According to a file guild, check a Fv file device path is valid. If it is invalid,
1934 try to return the valid device path.
1935 FV address maybe changes for memory layout adjust from time to time, use this function
1936 could promise the Fv file device path is right.
1937
1938 @param DevicePath on input, the Fv file device path need to check on
1939 output, the updated valid Fv file device path
1940 @param FileGuid the Fv file guild
1941
1942 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1943 parameter
1944 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1945 guild at all
1946 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1947 valid
1948 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1949 and return the updated device path in DevicePath
1950
1951**/
1952EFI_STATUS
1953EFIAPI
1954BdsLibUpdateFvFileDevicePath (
1955 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
1956 IN EFI_GUID *FileGuid
1957 )
1958{
1959 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1960 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1961 EFI_STATUS Status;
1962 EFI_GUID *GuidPoint;
1963 UINTN Index;
1964 UINTN FvHandleCount;
1965 EFI_HANDLE *FvHandleBuffer;
1966 EFI_FV_FILETYPE Type;
1967 UINTN Size;
1968 EFI_FV_FILE_ATTRIBUTES Attributes;
1969 UINT32 AuthenticationStatus;
1970 BOOLEAN FindFvFile;
1971 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1972 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1973 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
1974 EFI_HANDLE FoundFvHandle;
1975 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
1976
1977 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
1978 return EFI_INVALID_PARAMETER;
1979 }
1980 if (FileGuid == NULL) {
1981 return EFI_INVALID_PARAMETER;
1982 }
1983
1984 //
1985 // Check whether the device path point to the default the input Fv file
1986 //
1987 TempDevicePath = *DevicePath;
1988 LastDeviceNode = TempDevicePath;
1989 while (!IsDevicePathEnd (TempDevicePath)) {
1990 LastDeviceNode = TempDevicePath;
1991 TempDevicePath = NextDevicePathNode (TempDevicePath);
1992 }
1993 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
1994 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
1995 );
1996 if (GuidPoint == NULL) {
1997 //
1998 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1999 //
2000 return EFI_UNSUPPORTED;
2001 }
2002 if (!CompareGuid (GuidPoint, FileGuid)) {
2003 //
2004 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
2005 //
2006 return EFI_UNSUPPORTED;
2007 }
2008
2009 //
2010 // Check whether the input Fv file device path is valid
2011 //
2012 TempDevicePath = *DevicePath;
2013 FoundFvHandle = NULL;
2014 Status = gBS->LocateDevicePath (
2015 &gEfiFirmwareVolume2ProtocolGuid,
2016 &TempDevicePath,
2017 &FoundFvHandle
2018 );
2019 if (!EFI_ERROR (Status)) {
2020 Status = gBS->HandleProtocol (
2021 FoundFvHandle,
2022 &gEfiFirmwareVolume2ProtocolGuid,
2023 (VOID **) &Fv
2024 );
2025 if (!EFI_ERROR (Status)) {
2026 //
2027 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
2028 //
2029 Status = Fv->ReadFile (
2030 Fv,
2031 FileGuid,
2032 NULL,
2033 &Size,
2034 &Type,
2035 &Attributes,
2036 &AuthenticationStatus
2037 );
2038 if (!EFI_ERROR (Status)) {
2039 return EFI_ALREADY_STARTED;
2040 }
2041 }
2042 }
2043
2044 //
2045 // Look for the input wanted FV file in current FV
2046 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
2047 //
2048 FindFvFile = FALSE;
2049 FoundFvHandle = NULL;
2050 Status = gBS->HandleProtocol (
2051 mBdsImageHandle,
2052 &gEfiLoadedImageProtocolGuid,
2053 (VOID **) &LoadedImage
2054 );
2055 if (!EFI_ERROR (Status)) {
2056 Status = gBS->HandleProtocol (
2057 LoadedImage->DeviceHandle,
2058 &gEfiFirmwareVolume2ProtocolGuid,
2059 (VOID **) &Fv
2060 );
2061 if (!EFI_ERROR (Status)) {
2062 Status = Fv->ReadFile (
2063 Fv,
2064 FileGuid,
2065 NULL,
2066 &Size,
2067 &Type,
2068 &Attributes,
2069 &AuthenticationStatus
2070 );
2071 if (!EFI_ERROR (Status)) {
2072 FindFvFile = TRUE;
2073 FoundFvHandle = LoadedImage->DeviceHandle;
2074 }
2075 }
2076 }
2077 //
2078 // Second, if fail to find, try to enumerate all FV
2079 //
2080 if (!FindFvFile) {
2081 FvHandleBuffer = NULL;
2082 gBS->LocateHandleBuffer (
2083 ByProtocol,
2084 &gEfiFirmwareVolume2ProtocolGuid,
2085 NULL,
2086 &FvHandleCount,
2087 &FvHandleBuffer
2088 );
2089 for (Index = 0; Index < FvHandleCount; Index++) {
2090 gBS->HandleProtocol (
2091 FvHandleBuffer[Index],
2092 &gEfiFirmwareVolume2ProtocolGuid,
2093 (VOID **) &Fv
2094 );
2095
2096 Status = Fv->ReadFile (
2097 Fv,
2098 FileGuid,
2099 NULL,
2100 &Size,
2101 &Type,
2102 &Attributes,
2103 &AuthenticationStatus
2104 );
2105 if (EFI_ERROR (Status)) {
2106 //
2107 // Skip if input Fv file not in the FV
2108 //
2109 continue;
2110 }
2111 FindFvFile = TRUE;
2112 FoundFvHandle = FvHandleBuffer[Index];
2113 break;
2114 }
2115
2116 if (FvHandleBuffer != NULL) {
2117 FreePool (FvHandleBuffer);
2118 }
2119 }
2120
2121 if (FindFvFile) {
2122 //
2123 // Build the shell device path
2124 //
2125 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
2126 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
2127 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
2128 *DevicePath = NewDevicePath;
2129 return EFI_SUCCESS;
2130 }
2131 return EFI_NOT_FOUND;
2132}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette