]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
Add support for BootOption with USB Class or USB WWID device path node.
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsBoot.c
1 /** @file
2 BDS Lib functions which relate with create or process the boot option.
3
4 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "InternalBdsLib.h"
16 #include "String.h"
17
18 BOOLEAN mEnumBootDevice = FALSE;
19 EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;
20
21 ///
22 /// This GUID is used for an EFI Variable that stores the front device pathes
23 /// for a partial device path that starts with the HD node.
24 ///
25 EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
26
27 ///
28 /// This GUID is used for register UNI string.
29 ///
30 EFI_GUID mBdsLibStringPackGuid = { 0x3b4d9b23, 0x95ac, 0x44f6, { 0x9f, 0xcd, 0xe, 0x95, 0x94, 0x58, 0x6c, 0x72 } };
31
32 ///
33 /// This GUID is used for Set/Get platform language into/from variable at last time enumeration to ensure the enumeration will
34 /// only execute once.
35 ///
36 EFI_GUID mBdsLibLastLangGuid = { 0xe8c545b, 0xa2ee, 0x470d, { 0x8e, 0x26, 0xbd, 0xa1, 0xa1, 0x3c, 0xa, 0xa3 } };
37
38 /**
39 The constructor function register UNI strings into imageHandle.
40
41 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
42
43 @param ImageHandle The firmware allocated handle for the EFI image.
44 @param SystemTable A pointer to the EFI System Table.
45
46 @retval EFI_SUCCESS The constructor successfully added string package.
47 @retval Other value The constructor can't add string package.
48
49 **/
50 EFI_STATUS
51 EFIAPI
52 GenericBdsLibConstructor (
53 IN EFI_HANDLE ImageHandle,
54 IN EFI_SYSTEM_TABLE *SystemTable
55 )
56 {
57
58 gBdsLibStringPackHandle = HiiAddPackages (
59 &mBdsLibStringPackGuid,
60 &ImageHandle,
61 GenericBdsLibStrings,
62 NULL
63 );
64
65 ASSERT (gBdsLibStringPackHandle != NULL);
66
67 return EFI_SUCCESS;
68 }
69
70
71
72 /**
73 Boot the legacy system with the boot option
74
75 @param Option The legacy boot option which have BBS device path
76
77 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
78 legacy boot.
79 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
80
81 **/
82 EFI_STATUS
83 BdsLibDoLegacyBoot (
84 IN BDS_COMMON_OPTION *Option
85 )
86 {
87 EFI_STATUS Status;
88 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
89
90 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
91 if (EFI_ERROR (Status)) {
92 //
93 // If no LegacyBios protocol we do not support legacy boot
94 //
95 return EFI_UNSUPPORTED;
96 }
97 //
98 // Notes: if we separate the int 19, then we don't need to refresh BBS
99 //
100 BdsRefreshBbsTableForBoot (Option);
101
102 //
103 // Write boot to OS performance data for legacy boot.
104 //
105 PERF_CODE (
106 WriteBootToOsPerformanceData ();
107 );
108
109 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
110 return LegacyBios->LegacyBoot (
111 LegacyBios,
112 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
113 Option->LoadOptionsSize,
114 Option->LoadOptions
115 );
116 }
117
118 /**
119 Internal function to check if the input boot option is a valid EFI NV Boot####.
120
121 @param OptionToCheck Boot option to be checked.
122
123 @retval TRUE This boot option matches a valid EFI NV Boot####.
124 @retval FALSE If not.
125
126 **/
127 BOOLEAN
128 IsBootOptionValidNVVarialbe (
129 IN BDS_COMMON_OPTION *OptionToCheck
130 )
131 {
132 LIST_ENTRY TempList;
133 BDS_COMMON_OPTION *BootOption;
134 BOOLEAN Valid;
135 CHAR16 OptionName[20];
136
137 Valid = FALSE;
138
139 InitializeListHead (&TempList);
140 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
141
142 BootOption = BdsLibVariableToOption (&TempList, OptionName);
143 if (BootOption == NULL) {
144 return FALSE;
145 }
146
147 //
148 // If the Boot Option Number and Device Path matches, OptionToCheck matches a
149 // valid EFI NV Boot####.
150 //
151 if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
152 (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
153 {
154 Valid = TRUE;
155 }
156
157 FreePool (BootOption);
158
159 return Valid;
160 }
161
162 /**
163 Check whether a USB device match the specified USB Class device path. This
164 function follows "Load Option Processing" behavior in UEFI specification.
165
166 @param UsbIo USB I/O protocol associated with the USB device.
167 @param UsbClass The USB Class device path to match.
168
169 @retval TRUE The USB device match the USB Class device path.
170 @retval FALSE The USB device does not match the USB Class device path.
171
172 **/
173 BOOLEAN
174 BdsMatchUsbClass (
175 IN EFI_USB_IO_PROTOCOL *UsbIo,
176 IN USB_CLASS_DEVICE_PATH *UsbClass
177 )
178 {
179 EFI_STATUS Status;
180 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
181 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
182 UINT8 DeviceClass;
183 UINT8 DeviceSubClass;
184 UINT8 DeviceProtocol;
185
186 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
187 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
188 return FALSE;
189 }
190
191 //
192 // Check Vendor Id and Product Id.
193 //
194 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
195 if (EFI_ERROR (Status)) {
196 return FALSE;
197 }
198
199 if ((UsbClass->VendorId != 0xffff) &&
200 (UsbClass->VendorId != DevDesc.IdVendor)) {
201 return FALSE;
202 }
203
204 if ((UsbClass->ProductId != 0xffff) &&
205 (UsbClass->ProductId != DevDesc.IdProduct)) {
206 return FALSE;
207 }
208
209 DeviceClass = DevDesc.DeviceClass;
210 DeviceSubClass = DevDesc.DeviceSubClass;
211 DeviceProtocol = DevDesc.DeviceProtocol;
212 if (DeviceClass == 0) {
213 //
214 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
215 // Protocol in Interface Descriptor instead.
216 //
217 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
218 if (EFI_ERROR (Status)) {
219 return FALSE;
220 }
221
222 DeviceClass = IfDesc.InterfaceClass;
223 DeviceSubClass = IfDesc.InterfaceSubClass;
224 DeviceProtocol = IfDesc.InterfaceProtocol;
225 }
226
227 //
228 // Check Class, SubClass and Protocol.
229 //
230 if ((UsbClass->DeviceClass != 0xff) &&
231 (UsbClass->DeviceClass != DeviceClass)) {
232 return FALSE;
233 }
234
235 if ((UsbClass->DeviceSubClass != 0xff) &&
236 (UsbClass->DeviceSubClass != DeviceSubClass)) {
237 return FALSE;
238 }
239
240 if ((UsbClass->DeviceProtocol != 0xff) &&
241 (UsbClass->DeviceProtocol != DeviceProtocol)) {
242 return FALSE;
243 }
244
245 return TRUE;
246 }
247
248 /**
249 Check whether a USB device match the specified USB WWID device path. This
250 function follows "Load Option Processing" behavior in UEFI specification.
251
252 @param UsbIo USB I/O protocol associated with the USB device.
253 @param UsbWwid The USB WWID device path to match.
254
255 @retval TRUE The USB device match the USB WWID device path.
256 @retval FALSE The USB device does not match the USB WWID device path.
257
258 **/
259 BOOLEAN
260 BdsMatchUsbWwid (
261 IN EFI_USB_IO_PROTOCOL *UsbIo,
262 IN USB_WWID_DEVICE_PATH *UsbWwid
263 )
264 {
265 EFI_STATUS Status;
266 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
267 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
268 UINT16 *LangIdTable;
269 UINT16 TableSize;
270 UINT16 Index;
271 CHAR16 *CompareStr;
272 UINTN CompareLen;
273 CHAR16 *SerialNumberStr;
274 UINTN Length;
275
276 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
277 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){
278 return FALSE;
279 }
280
281 //
282 // Check Vendor Id and Product Id.
283 //
284 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
285 if (EFI_ERROR (Status)) {
286 return FALSE;
287 }
288 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
289 (DevDesc.IdProduct != UsbWwid->ProductId)) {
290 return FALSE;
291 }
292
293 //
294 // Check Interface Number.
295 //
296 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
297 if (EFI_ERROR (Status)) {
298 return FALSE;
299 }
300 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
301 return FALSE;
302 }
303
304 //
305 // Check Serial Number.
306 //
307 if (DevDesc.StrSerialNumber == 0) {
308 return FALSE;
309 }
310
311 //
312 // Get all supported languages.
313 //
314 TableSize = 0;
315 LangIdTable = NULL;
316 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
317 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
318 return FALSE;
319 }
320
321 //
322 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
323 //
324 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
325 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
326 if (CompareStr[CompareLen - 1] == L'\0') {
327 CompareLen--;
328 }
329
330 //
331 // Compare serial number in each supported language.
332 //
333 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
334 SerialNumberStr = NULL;
335 Status = UsbIo->UsbGetStringDescriptor (
336 UsbIo,
337 LangIdTable[Index],
338 DevDesc.StrSerialNumber,
339 &SerialNumberStr
340 );
341 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
342 continue;
343 }
344
345 Length = StrLen (SerialNumberStr);
346 if ((Length >= CompareLen) &&
347 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
348 FreePool (SerialNumberStr);
349 return TRUE;
350 }
351
352 FreePool (SerialNumberStr);
353 }
354
355 return FALSE;
356 }
357
358 /**
359 Find a USB device which match the specified short-form device path start with
360 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
361 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
362 this function will only search in its child devices.
363
364 @param ParentDevicePath The device path of the parent.
365 @param ShortFormDevicePath The USB Class or USB WWID device path to match.
366
367 @return The handle of matched USB device, or NULL if not found.
368
369 **/
370 EFI_HANDLE *
371 BdsFindUsbDevice (
372 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
373 IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath
374 )
375 {
376 EFI_STATUS Status;
377 UINTN UsbIoHandleCount;
378 EFI_HANDLE *UsbIoHandleBuffer;
379 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
380 EFI_USB_IO_PROTOCOL *UsbIo;
381 UINTN Index;
382 UINTN ParentSize;
383 UINTN Size;
384 EFI_HANDLE ReturnHandle;
385
386 //
387 // Get all UsbIo Handles.
388 //
389 UsbIoHandleCount = 0;
390 UsbIoHandleBuffer = NULL;
391 Status = gBS->LocateHandleBuffer (
392 ByProtocol,
393 &gEfiUsbIoProtocolGuid,
394 NULL,
395 &UsbIoHandleCount,
396 &UsbIoHandleBuffer
397 );
398 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
399 return NULL;
400 }
401
402 ReturnHandle = NULL;
403 ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
404 for (Index = 0; Index < UsbIoHandleCount; Index++) {
405 //
406 // Get the Usb IO interface.
407 //
408 Status = gBS->HandleProtocol(
409 UsbIoHandleBuffer[Index],
410 &gEfiUsbIoProtocolGuid,
411 (VOID **) &UsbIo
412 );
413 if (EFI_ERROR (Status)) {
414 continue;
415 }
416
417 if (ParentDevicePath != NULL) {
418 //
419 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
420 //
421 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
422 ASSERT (UsbIoDevicePath != NULL);
423
424 Size = GetDevicePathSize (UsbIoDevicePath);
425 if ((Size < ParentSize) ||
426 (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
427 continue;
428 }
429 }
430
431 if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
432 BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
433 ReturnHandle = UsbIoHandleBuffer[Index];
434 break;
435 }
436 }
437
438 FreePool (UsbIoHandleBuffer);
439 return ReturnHandle;
440 }
441
442 /**
443 Expand USB Class or USB WWID device path node to be full device path of a USB
444 device in platform.
445
446 This function support following 4 cases:
447 1) Boot Option device path starts with a USB Class or USB WWID device path,
448 and there is no Media FilePath device path in the end.
449 In this case, it will follow Removable Media Boot Behavior.
450 2) Boot Option device path starts with a USB Class or USB WWID device path,
451 and ended with Media FilePath device path.
452 3) Boot Option device path starts with a full device path to a USB Host Controller,
453 contains a USB Class or USB WWID device path node, while not ended with Media
454 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
455 4) Boot Option device path starts with a full device path to a USB Host Controller,
456 contains a USB Class or USB WWID device path node, and ended with Media
457 FilePath device path.
458
459 @param DevicePath The Boot Option device path.
460
461 @return The full device path after expanding, or NULL if there is no USB Class
462 or USB WWID device path found, or USB Class or USB WWID device path
463 was found but failed to expand it.
464
465 **/
466 EFI_DEVICE_PATH_PROTOCOL *
467 BdsExpandUsbShortFormDevicePath (
468 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
469 )
470 {
471 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
472 EFI_HANDLE *UsbIoHandle;
473 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
474 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
475 EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;
476 EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;
477
478 //
479 // Search for USB Class or USB WWID device path node.
480 //
481 ShortFormDevicePath = NULL;
482 TempDevicePath = DevicePath;
483 while (!IsDevicePathEnd (TempDevicePath)) {
484 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
485 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
486 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
487 ShortFormDevicePath = TempDevicePath;
488 break;
489 }
490
491 TempDevicePath = NextDevicePathNode (TempDevicePath);
492 }
493
494 if (ShortFormDevicePath == NULL) {
495 //
496 // No USB Class or USB WWID device path node found, do nothing.
497 //
498 return NULL;
499 }
500
501 if (ShortFormDevicePath == DevicePath) {
502 //
503 // Boot Option device path starts with USB Class or USB WWID device path.
504 //
505 UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
506 if (UsbIoHandle == NULL) {
507 //
508 // Failed to find a match in existing devices, connect the short form USB
509 // device path and try again.
510 //
511 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
512 UsbIoHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
513 }
514 } else {
515 //
516 // Boot Option device path contains USB Class or USB WWID device path node.
517 //
518
519 //
520 // Prepare the parent device path for search.
521 //
522 TempDevicePath = DuplicateDevicePath (DevicePath);
523 ASSERT (TempDevicePath != NULL);
524 SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
525
526 //
527 // The USB Host Controller device path is in already in Boot Option device path
528 // and USB Bus driver already support RemainingDevicePath starts with USB
529 // Class or USB WWID device path, so just search in existing USB devices and
530 // doesn't perform ConnectController here.
531 //
532 UsbIoHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
533 FreePool (TempDevicePath);
534 }
535
536 if (UsbIoHandle == NULL) {
537 //
538 // Failed to expand USB Class or USB WWID device path.
539 //
540 return NULL;
541 }
542
543 //
544 // Get device path of the matched USB device.
545 //
546 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandle);
547 ASSERT (UsbIoDevicePath != NULL);
548
549 FullDevicePath = NULL;
550 //
551 // Advance to next device path node to skip the USB Class or USB WWID device path.
552 //
553 NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
554 if (!IsDevicePathEnd (NextDevicePath)) {
555 //
556 // There is remaining device path after USB Class or USB WWID device path
557 // node, append it to the USB device path.
558 //
559 FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
560
561 //
562 // Connect the full device path, so that Simple File System protocol
563 // could be installed for this USB device.
564 //
565 BdsLibConnectDevicePath (FullDevicePath);
566 } else {
567 //
568 // USB Class or WWID device path is in the end.
569 //
570 FullDevicePath = UsbIoDevicePath;
571 }
572
573 return FullDevicePath;
574 }
575
576 /**
577 Process the boot option follow the UEFI specification and
578 special treat the legacy boot option with BBS_DEVICE_PATH.
579
580 @param Option The boot option need to be processed
581 @param DevicePath The device path which describe where to load the
582 boot image or the legacy BBS device path to boot
583 the legacy OS
584 @param ExitDataSize The size of exit data.
585 @param ExitData Data returned when Boot image failed.
586
587 @retval EFI_SUCCESS Boot from the input boot option successfully.
588 @retval EFI_NOT_FOUND If the Device Path is not found in the system
589
590 **/
591 EFI_STATUS
592 EFIAPI
593 BdsLibBootViaBootOption (
594 IN BDS_COMMON_OPTION *Option,
595 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
596 OUT UINTN *ExitDataSize,
597 OUT CHAR16 **ExitData OPTIONAL
598 )
599 {
600 EFI_STATUS Status;
601 EFI_HANDLE Handle;
602 EFI_HANDLE ImageHandle;
603 EFI_DEVICE_PATH_PROTOCOL *FilePath;
604 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
605 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
606 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
607 LIST_ENTRY TempBootLists;
608
609 //
610 // Record the performance data for End of BDS
611 //
612 PERF_END(NULL, "BDS", NULL, 0);
613
614 *ExitDataSize = 0;
615 *ExitData = NULL;
616
617 //
618 // Notes: this code can be remove after the s3 script table
619 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
620 // EVT_SIGNAL_LEGACY_BOOT
621 //
622 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
623 if (!EFI_ERROR (Status)) {
624 AcpiS3Save->S3Save (AcpiS3Save, NULL);
625 }
626 //
627 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
628 // full device path
629 //
630 WorkingDevicePath = NULL;
631 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
632 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
633 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
634 (HARDDRIVE_DEVICE_PATH *)DevicePath
635 );
636 if (WorkingDevicePath != NULL) {
637 DevicePath = WorkingDevicePath;
638 }
639 }
640
641 //
642 // Expand USB Class or USB WWID drive path node to full device path.
643 //
644 WorkingDevicePath = BdsExpandUsbShortFormDevicePath (DevicePath);
645 if (WorkingDevicePath != NULL) {
646 DevicePath = WorkingDevicePath;
647 }
648
649 //
650 // Signal the EVT_SIGNAL_READY_TO_BOOT event
651 //
652 EfiSignalEventReadyToBoot();
653
654 //
655 // Adjust the different type memory page number just before booting
656 // and save the updated info into the variable for next boot to use
657 //
658 BdsSetMemoryTypeInformationVariable ();
659
660
661 //
662 // Set Boot Current
663 //
664 if (IsBootOptionValidNVVarialbe (Option)) {
665 //
666 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
667 // In this case, "BootCurrent" is not created.
668 // Only create the BootCurrent variable when it points to a valid Boot#### variable.
669 //
670 gRT->SetVariable (
671 L"BootCurrent",
672 &gEfiGlobalVariableGuid,
673 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
674 sizeof (UINT16),
675 &Option->BootCurrent
676 );
677 }
678
679 ASSERT (Option->DevicePath != NULL);
680 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
681 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
682 ) {
683 //
684 // Check to see if we should legacy BOOT. If yes then do the legacy boot
685 //
686 return BdsLibDoLegacyBoot (Option);
687 }
688
689 //
690 // If the boot option point to Internal FV shell, make sure it is valid
691 //
692 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
693 if (!EFI_ERROR(Status)) {
694 if (Option->DevicePath != NULL) {
695 FreePool(Option->DevicePath);
696 }
697 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
698 ASSERT(Option->DevicePath != NULL);
699 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
700 //
701 // Update the shell boot option
702 //
703 InitializeListHead (&TempBootLists);
704 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
705
706 //
707 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
708 //
709 FreePool (DevicePath);
710 DevicePath = Option->DevicePath;
711 }
712
713 DEBUG_CODE_BEGIN();
714
715 if (Option->Description == NULL) {
716 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
717 } else {
718 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
719 }
720
721 DEBUG_CODE_END();
722
723 Status = gBS->LoadImage (
724 TRUE,
725 gImageHandle,
726 DevicePath,
727 NULL,
728 0,
729 &ImageHandle
730 );
731
732 //
733 // If we didn't find an image directly, we need to try as if it is a removable device boot option
734 // and load the image according to the default boot behavior for removable device.
735 //
736 if (EFI_ERROR (Status)) {
737 //
738 // check if there is a bootable removable media could be found in this device path ,
739 // and get the bootable media handle
740 //
741 Handle = BdsLibGetBootableHandle(DevicePath);
742 if (Handle == NULL) {
743 goto Done;
744 }
745 //
746 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
747 // machinename is ia32, ia64, x64, ...
748 //
749 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
750 if (FilePath != NULL) {
751 Status = gBS->LoadImage (
752 TRUE,
753 gImageHandle,
754 FilePath,
755 NULL,
756 0,
757 &ImageHandle
758 );
759 if (EFI_ERROR (Status)) {
760 //
761 // The DevicePath failed, and it's not a valid
762 // removable media device.
763 //
764 goto Done;
765 }
766 }
767 }
768
769 if (EFI_ERROR (Status)) {
770 //
771 // It there is any error from the Boot attempt exit now.
772 //
773 goto Done;
774 }
775 //
776 // Provide the image with it's load options
777 //
778 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
779 ASSERT_EFI_ERROR (Status);
780
781 if (Option->LoadOptionsSize != 0) {
782 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
783 ImageInfo->LoadOptions = Option->LoadOptions;
784 }
785 //
786 // Before calling the image, enable the Watchdog Timer for
787 // the 5 Minute period
788 //
789 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
790
791 //
792 // Write boot to OS performance data for UEFI boot
793 //
794 PERF_CODE (
795 WriteBootToOsPerformanceData ();
796 );
797
798 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
799 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
800
801 //
802 // Clear the Watchdog Timer after the image returns
803 //
804 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
805
806 Done:
807 //
808 // Clear Boot Current
809 //
810 gRT->SetVariable (
811 L"BootCurrent",
812 &gEfiGlobalVariableGuid,
813 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
814 0,
815 &Option->BootCurrent
816 );
817
818 return Status;
819 }
820
821
822 /**
823 Expand a device path that starts with a hard drive media device path node to be a
824 full device path that includes the full hardware path to the device. We need
825 to do this so it can be booted. As an optimization the front match (the part point
826 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
827 so a connect all is not required on every boot. All successful history device path
828 which point to partition node (the front part) will be saved.
829
830 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
831 drive media device path.
832 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
833 cannot be found.
834
835 **/
836 EFI_DEVICE_PATH_PROTOCOL *
837 EFIAPI
838 BdsExpandPartitionPartialDevicePathToFull (
839 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
840 )
841 {
842 EFI_STATUS Status;
843 UINTN BlockIoHandleCount;
844 EFI_HANDLE *BlockIoBuffer;
845 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
846 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
847 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
848 UINTN Index;
849 UINTN InstanceNum;
850 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
851 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
852 UINTN CachedDevicePathSize;
853 BOOLEAN DeviceExist;
854 BOOLEAN NeedAdjust;
855 EFI_DEVICE_PATH_PROTOCOL *Instance;
856 UINTN Size;
857
858 FullDevicePath = NULL;
859 //
860 // Check if there is prestore 'HDDP' variable.
861 // If exist, search the front path which point to partition node in the variable instants.
862 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
863 //
864 CachedDevicePath = BdsLibGetVariableAndSize (
865 L"HDDP",
866 &mHdBootVariablePrivateGuid,
867 &CachedDevicePathSize
868 );
869
870 if (CachedDevicePath != NULL) {
871 TempNewDevicePath = CachedDevicePath;
872 DeviceExist = FALSE;
873 NeedAdjust = FALSE;
874 do {
875 //
876 // Check every instance of the variable
877 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
878 // partial partition boot option. Second, check whether the instance could be connected.
879 //
880 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
881 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
882 //
883 // Connect the device path instance, the device path point to hard drive media device path node
884 // e.g. ACPI() /PCI()/ATA()/Partition()
885 //
886 Status = BdsLibConnectDevicePath (Instance);
887 if (!EFI_ERROR (Status)) {
888 DeviceExist = TRUE;
889 break;
890 }
891 }
892 //
893 // Come here means the first instance is not matched
894 //
895 NeedAdjust = TRUE;
896 FreePool(Instance);
897 } while (TempNewDevicePath != NULL);
898
899 if (DeviceExist) {
900 //
901 // Find the matched device path.
902 // Append the file path information from the boot option and return the fully expanded device path.
903 //
904 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
905 FullDevicePath = AppendDevicePath (Instance, DevicePath);
906
907 //
908 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
909 //
910 if (NeedAdjust) {
911 //
912 // First delete the matched instance.
913 //
914 TempNewDevicePath = CachedDevicePath;
915 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
916 FreePool (TempNewDevicePath);
917
918 //
919 // Second, append the remaining path after the matched instance
920 //
921 TempNewDevicePath = CachedDevicePath;
922 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
923 FreePool (TempNewDevicePath);
924 //
925 // Save the matching Device Path so we don't need to do a connect all next time
926 //
927 Status = gRT->SetVariable (
928 L"HDDP",
929 &mHdBootVariablePrivateGuid,
930 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
931 GetDevicePathSize (CachedDevicePath),
932 CachedDevicePath
933 );
934 }
935
936 FreePool (Instance);
937 FreePool (CachedDevicePath);
938 return FullDevicePath;
939 }
940 }
941
942 //
943 // If we get here we fail to find or 'HDDP' not exist, and now we need
944 // to search all devices in the system for a matched partition
945 //
946 BdsLibConnectAllDriversToAllControllers ();
947 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
948 if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
949 //
950 // If there was an error or there are no device handles that support
951 // the BLOCK_IO Protocol, then return.
952 //
953 return NULL;
954 }
955 //
956 // Loop through all the device handles that support the BLOCK_IO Protocol
957 //
958 for (Index = 0; Index < BlockIoHandleCount; Index++) {
959
960 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
961 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
962 continue;
963 }
964
965 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
966 //
967 // Find the matched partition device path
968 //
969 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
970 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
971
972 //
973 // Save the matched partition device path in 'HDDP' variable
974 //
975 if (CachedDevicePath != NULL) {
976 //
977 // Save the matched partition device path as first instance of 'HDDP' variable
978 //
979 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
980 TempNewDevicePath = CachedDevicePath;
981 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
982 FreePool(TempNewDevicePath);
983
984 TempNewDevicePath = CachedDevicePath;
985 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
986 if (TempNewDevicePath != NULL) {
987 FreePool(TempNewDevicePath);
988 }
989 } else {
990 TempNewDevicePath = CachedDevicePath;
991 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
992 FreePool(TempNewDevicePath);
993 }
994 //
995 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
996 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
997 //
998 InstanceNum = 0;
999 ASSERT (CachedDevicePath != NULL);
1000 TempNewDevicePath = CachedDevicePath;
1001 while (!IsDevicePathEnd (TempNewDevicePath)) {
1002 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
1003 //
1004 // Parse one instance
1005 //
1006 while (!IsDevicePathEndType (TempNewDevicePath)) {
1007 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
1008 }
1009 InstanceNum++;
1010 //
1011 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1012 //
1013 if (InstanceNum >= 12) {
1014 SetDevicePathEndNode (TempNewDevicePath);
1015 break;
1016 }
1017 }
1018 } else {
1019 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
1020 }
1021
1022 //
1023 // Save the matching Device Path so we don't need to do a connect all next time
1024 //
1025 Status = gRT->SetVariable (
1026 L"HDDP",
1027 &mHdBootVariablePrivateGuid,
1028 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1029 GetDevicePathSize (CachedDevicePath),
1030 CachedDevicePath
1031 );
1032
1033 break;
1034 }
1035 }
1036
1037 if (CachedDevicePath != NULL) {
1038 FreePool (CachedDevicePath);
1039 }
1040 if (BlockIoBuffer != NULL) {
1041 FreePool (BlockIoBuffer);
1042 }
1043 return FullDevicePath;
1044 }
1045
1046 /**
1047 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1048 instances, has the same partition node with HardDriveDevicePath device path
1049
1050 @param BlockIoDevicePath Multi device path instances which need to check
1051 @param HardDriveDevicePath A device path which starts with a hard drive media
1052 device path.
1053
1054 @retval TRUE There is a matched device path instance.
1055 @retval FALSE There is no matched device path instance.
1056
1057 **/
1058 BOOLEAN
1059 EFIAPI
1060 MatchPartitionDevicePathNode (
1061 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
1062 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
1063 )
1064 {
1065 HARDDRIVE_DEVICE_PATH *TmpHdPath;
1066 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1067 BOOLEAN Match;
1068 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
1069
1070 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
1071 return FALSE;
1072 }
1073
1074 //
1075 // Make PreviousDevicePath == the device path node before the end node
1076 //
1077 DevicePath = BlockIoDevicePath;
1078 BlockIoHdDevicePathNode = NULL;
1079
1080 //
1081 // find the partition device path node
1082 //
1083 while (!IsDevicePathEnd (DevicePath)) {
1084 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
1085 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
1086 ) {
1087 BlockIoHdDevicePathNode = DevicePath;
1088 break;
1089 }
1090
1091 DevicePath = NextDevicePathNode (DevicePath);
1092 }
1093
1094 if (BlockIoHdDevicePathNode == NULL) {
1095 return FALSE;
1096 }
1097 //
1098 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1099 //
1100 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
1101 Match = FALSE;
1102
1103 //
1104 // Check for the match
1105 //
1106 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
1107 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
1108 switch (TmpHdPath->SignatureType) {
1109 case SIGNATURE_TYPE_GUID:
1110 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
1111 break;
1112 case SIGNATURE_TYPE_MBR:
1113 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
1114 break;
1115 default:
1116 Match = FALSE;
1117 break;
1118 }
1119 }
1120
1121 return Match;
1122 }
1123
1124 /**
1125 Delete the boot option associated with the handle passed in.
1126
1127 @param Handle The handle which present the device path to create
1128 boot option
1129
1130 @retval EFI_SUCCESS Delete the boot option success
1131 @retval EFI_NOT_FOUND If the Device Path is not found in the system
1132 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
1133 @retval Other Error return value from SetVariable()
1134
1135 **/
1136 EFI_STATUS
1137 BdsLibDeleteOptionFromHandle (
1138 IN EFI_HANDLE Handle
1139 )
1140 {
1141 UINT16 *BootOrder;
1142 UINT8 *BootOptionVar;
1143 UINTN BootOrderSize;
1144 UINTN BootOptionSize;
1145 EFI_STATUS Status;
1146 UINTN Index;
1147 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
1148 UINTN DevicePathSize;
1149 UINTN OptionDevicePathSize;
1150 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1151 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
1152 UINT8 *TempPtr;
1153
1154 Status = EFI_SUCCESS;
1155 BootOrder = NULL;
1156 BootOrderSize = 0;
1157
1158 //
1159 // Check "BootOrder" variable, if no, means there is no any boot order.
1160 //
1161 BootOrder = BdsLibGetVariableAndSize (
1162 L"BootOrder",
1163 &gEfiGlobalVariableGuid,
1164 &BootOrderSize
1165 );
1166 if (BootOrder == NULL) {
1167 return EFI_NOT_FOUND;
1168 }
1169
1170 //
1171 // Convert device handle to device path protocol instance
1172 //
1173 DevicePath = DevicePathFromHandle (Handle);
1174 if (DevicePath == NULL) {
1175 return EFI_NOT_FOUND;
1176 }
1177 DevicePathSize = GetDevicePathSize (DevicePath);
1178
1179 //
1180 // Loop all boot order variable and find the matching device path
1181 //
1182 Index = 0;
1183 while (Index < BootOrderSize / sizeof (UINT16)) {
1184 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
1185 BootOptionVar = BdsLibGetVariableAndSize (
1186 BootOption,
1187 &gEfiGlobalVariableGuid,
1188 &BootOptionSize
1189 );
1190
1191 if (BootOptionVar == NULL) {
1192 FreePool (BootOrder);
1193 return EFI_OUT_OF_RESOURCES;
1194 }
1195
1196 TempPtr = BootOptionVar;
1197 TempPtr += sizeof (UINT32) + sizeof (UINT16);
1198 TempPtr += StrSize ((CHAR16 *) TempPtr);
1199 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
1200 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
1201
1202 //
1203 // Check whether the device path match
1204 //
1205 if ((OptionDevicePathSize == DevicePathSize) &&
1206 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
1207 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
1208 FreePool (BootOptionVar);
1209 break;
1210 }
1211
1212 FreePool (BootOptionVar);
1213 Index++;
1214 }
1215
1216 //
1217 // Adjust number of boot option for "BootOrder" variable.
1218 //
1219 Status = gRT->SetVariable (
1220 L"BootOrder",
1221 &gEfiGlobalVariableGuid,
1222 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1223 BootOrderSize,
1224 BootOrder
1225 );
1226
1227 FreePool (BootOrder);
1228
1229 return Status;
1230 }
1231
1232
1233 /**
1234 Delete all invalid EFI boot options.
1235
1236 @retval EFI_SUCCESS Delete all invalid boot option success
1237 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
1238 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
1239 @retval Other Error return value from SetVariable()
1240
1241 **/
1242 EFI_STATUS
1243 BdsDeleteAllInvalidEfiBootOption (
1244 VOID
1245 )
1246 {
1247 UINT16 *BootOrder;
1248 UINT8 *BootOptionVar;
1249 UINTN BootOrderSize;
1250 UINTN BootOptionSize;
1251 EFI_STATUS Status;
1252 UINTN Index;
1253 UINTN Index2;
1254 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
1255 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
1256 UINT8 *TempPtr;
1257 CHAR16 *Description;
1258
1259 Status = EFI_SUCCESS;
1260 BootOrder = NULL;
1261 BootOrderSize = 0;
1262
1263 //
1264 // Check "BootOrder" variable firstly, this variable hold the number of boot options
1265 //
1266 BootOrder = BdsLibGetVariableAndSize (
1267 L"BootOrder",
1268 &gEfiGlobalVariableGuid,
1269 &BootOrderSize
1270 );
1271 if (NULL == BootOrder) {
1272 return EFI_NOT_FOUND;
1273 }
1274
1275 Index = 0;
1276 while (Index < BootOrderSize / sizeof (UINT16)) {
1277 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
1278 BootOptionVar = BdsLibGetVariableAndSize (
1279 BootOption,
1280 &gEfiGlobalVariableGuid,
1281 &BootOptionSize
1282 );
1283 if (NULL == BootOptionVar) {
1284 FreePool (BootOrder);
1285 return EFI_OUT_OF_RESOURCES;
1286 }
1287
1288 TempPtr = BootOptionVar;
1289 TempPtr += sizeof (UINT32) + sizeof (UINT16);
1290 Description = (CHAR16 *) TempPtr;
1291 TempPtr += StrSize ((CHAR16 *) TempPtr);
1292 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
1293
1294 //
1295 // Skip legacy boot option (BBS boot device)
1296 //
1297 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
1298 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
1299 FreePool (BootOptionVar);
1300 Index++;
1301 continue;
1302 }
1303
1304 if (!BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
1305 //
1306 // Delete this invalid boot option "Boot####"
1307 //
1308 Status = gRT->SetVariable (
1309 BootOption,
1310 &gEfiGlobalVariableGuid,
1311 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1312 0,
1313 NULL
1314 );
1315 //
1316 // Mark this boot option in boot order as deleted
1317 //
1318 BootOrder[Index] = 0xffff;
1319 }
1320
1321 FreePool (BootOptionVar);
1322 Index++;
1323 }
1324
1325 //
1326 // Adjust boot order array
1327 //
1328 Index2 = 0;
1329 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
1330 if (BootOrder[Index] != 0xffff) {
1331 BootOrder[Index2] = BootOrder[Index];
1332 Index2 ++;
1333 }
1334 }
1335 Status = gRT->SetVariable (
1336 L"BootOrder",
1337 &gEfiGlobalVariableGuid,
1338 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1339 Index2 * sizeof (UINT16),
1340 BootOrder
1341 );
1342
1343 FreePool (BootOrder);
1344
1345 return Status;
1346 }
1347
1348
1349 /**
1350 For EFI boot option, BDS separate them as six types:
1351 1. Network - The boot option points to the SimpleNetworkProtocol device.
1352 Bds will try to automatically create this type boot option when enumerate.
1353 2. Shell - The boot option points to internal flash shell.
1354 Bds will try to automatically create this type boot option when enumerate.
1355 3. Removable BlockIo - The boot option only points to the removable media
1356 device, like USB flash disk, DVD, Floppy etc.
1357 These device should contain a *removable* blockIo
1358 protocol in their device handle.
1359 Bds will try to automatically create this type boot option
1360 when enumerate.
1361 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1362 like HardDisk.
1363 These device should contain a *fixed* blockIo
1364 protocol in their device handle.
1365 BDS will skip fixed blockIo devices, and NOT
1366 automatically create boot option for them. But BDS
1367 will help to delete those fixed blockIo boot option,
1368 whose description rule conflict with other auto-created
1369 boot options.
1370 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
1371 has SimpleFileSystem Protocol, but has no blockio
1372 protocol. These devices do not offer blockIo
1373 protocol, but BDS still can get the
1374 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
1375 Protocol.
1376 6. File - The boot option points to a file. These boot options are usually
1377 created by user manually or OS loader. BDS will not delete or modify
1378 these boot options.
1379
1380 This function will enumerate all possible boot device in the system, and
1381 automatically create boot options for Network, Shell, Removable BlockIo,
1382 and Non-BlockIo Simplefile devices.
1383 It will only execute once of every boot.
1384
1385 @param BdsBootOptionList The header of the link list which indexed all
1386 current boot options
1387
1388 @retval EFI_SUCCESS Finished all the boot device enumerate and create
1389 the boot option base on that boot device
1390
1391 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
1392 **/
1393 EFI_STATUS
1394 EFIAPI
1395 BdsLibEnumerateAllBootOption (
1396 IN OUT LIST_ENTRY *BdsBootOptionList
1397 )
1398 {
1399 EFI_STATUS Status;
1400 UINT16 FloppyNumber;
1401 UINT16 CdromNumber;
1402 UINT16 UsbNumber;
1403 UINT16 MiscNumber;
1404 UINT16 ScsiNumber;
1405 UINT16 NonBlockNumber;
1406 UINTN NumberBlockIoHandles;
1407 EFI_HANDLE *BlockIoHandles;
1408 EFI_BLOCK_IO_PROTOCOL *BlkIo;
1409 UINTN Index;
1410 UINTN NumOfLoadFileHandles;
1411 EFI_HANDLE *LoadFileHandles;
1412 UINTN FvHandleCount;
1413 EFI_HANDLE *FvHandleBuffer;
1414 EFI_FV_FILETYPE Type;
1415 UINTN Size;
1416 EFI_FV_FILE_ATTRIBUTES Attributes;
1417 UINT32 AuthenticationStatus;
1418 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1419 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1420 UINTN DevicePathType;
1421 CHAR16 Buffer[40];
1422 EFI_HANDLE *FileSystemHandles;
1423 UINTN NumberFileSystemHandles;
1424 BOOLEAN NeedDelete;
1425 EFI_IMAGE_DOS_HEADER DosHeader;
1426 CHAR8 *PlatLang;
1427 CHAR8 *LastLang;
1428 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1429 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1430
1431 FloppyNumber = 0;
1432 CdromNumber = 0;
1433 UsbNumber = 0;
1434 MiscNumber = 0;
1435 ScsiNumber = 0;
1436 PlatLang = NULL;
1437 LastLang = NULL;
1438 ZeroMem (Buffer, sizeof (Buffer));
1439
1440 //
1441 // If the boot device enumerate happened, just get the boot
1442 // device from the boot order variable
1443 //
1444 if (mEnumBootDevice) {
1445 LastLang = GetVariable (L"LastEnumLang", &mBdsLibLastLangGuid);
1446 PlatLang = GetEfiGlobalVariable (L"PlatformLang");
1447 ASSERT (PlatLang != NULL);
1448 if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {
1449 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1450 FreePool (LastLang);
1451 FreePool (PlatLang);
1452 return Status;
1453 } else {
1454 Status = gRT->SetVariable (
1455 L"LastEnumLang",
1456 &mBdsLibLastLangGuid,
1457 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1458 AsciiStrSize (PlatLang),
1459 PlatLang
1460 );
1461 ASSERT_EFI_ERROR (Status);
1462
1463 if (LastLang != NULL) {
1464 FreePool (LastLang);
1465 }
1466 FreePool (PlatLang);
1467 }
1468 }
1469
1470 //
1471 // Notes: this dirty code is to get the legacy boot option from the
1472 // BBS table and create to variable as the EFI boot option, it should
1473 // be removed after the CSM can provide legacy boot option directly
1474 //
1475 REFRESH_LEGACY_BOOT_OPTIONS;
1476
1477 //
1478 // Delete invalid boot option
1479 //
1480 BdsDeleteAllInvalidEfiBootOption ();
1481
1482 //
1483 // Parse removable media
1484 //
1485 gBS->LocateHandleBuffer (
1486 ByProtocol,
1487 &gEfiBlockIoProtocolGuid,
1488 NULL,
1489 &NumberBlockIoHandles,
1490 &BlockIoHandles
1491 );
1492
1493 for (Index = 0; Index < NumberBlockIoHandles; Index++) {
1494 Status = gBS->HandleProtocol (
1495 BlockIoHandles[Index],
1496 &gEfiBlockIoProtocolGuid,
1497 (VOID **) &BlkIo
1498 );
1499 if (!EFI_ERROR (Status)) {
1500 if (!BlkIo->Media->RemovableMedia) {
1501 //
1502 // skip the non-removable block devices
1503 //
1504 continue;
1505 }
1506 }
1507 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
1508 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
1509
1510 switch (DevicePathType) {
1511 case BDS_EFI_ACPI_FLOPPY_BOOT:
1512 if (FloppyNumber != 0) {
1513 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);
1514 } else {
1515 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));
1516 }
1517 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1518 FloppyNumber++;
1519 break;
1520
1521 //
1522 // Assume a removable SATA device should be the DVD/CD device
1523 //
1524 case BDS_EFI_MESSAGE_ATAPI_BOOT:
1525 case BDS_EFI_MESSAGE_SATA_BOOT:
1526 if (CdromNumber != 0) {
1527 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);
1528 } else {
1529 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));
1530 }
1531 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));
1532 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1533 CdromNumber++;
1534 break;
1535
1536 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
1537 if (UsbNumber != 0) {
1538 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);
1539 } else {
1540 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));
1541 }
1542 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1543 UsbNumber++;
1544 break;
1545
1546 case BDS_EFI_MESSAGE_SCSI_BOOT:
1547 if (ScsiNumber != 0) {
1548 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);
1549 } else {
1550 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));
1551 }
1552 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1553 ScsiNumber++;
1554 break;
1555
1556 case BDS_EFI_MESSAGE_MISC_BOOT:
1557 if (MiscNumber != 0) {
1558 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);
1559 } else {
1560 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));
1561 }
1562 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
1563 MiscNumber++;
1564 break;
1565
1566 default:
1567 break;
1568 }
1569 }
1570
1571 if (NumberBlockIoHandles != 0) {
1572 FreePool (BlockIoHandles);
1573 }
1574
1575 //
1576 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
1577 //
1578 NonBlockNumber = 0;
1579 gBS->LocateHandleBuffer (
1580 ByProtocol,
1581 &gEfiSimpleFileSystemProtocolGuid,
1582 NULL,
1583 &NumberFileSystemHandles,
1584 &FileSystemHandles
1585 );
1586 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
1587 Status = gBS->HandleProtocol (
1588 FileSystemHandles[Index],
1589 &gEfiBlockIoProtocolGuid,
1590 (VOID **) &BlkIo
1591 );
1592 if (!EFI_ERROR (Status)) {
1593 //
1594 // Skip if the file system handle supports a BlkIo protocol,
1595 //
1596 continue;
1597 }
1598
1599 //
1600 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
1601 // machinename is ia32, ia64, x64, ...
1602 //
1603 Hdr.Union = &HdrData;
1604 NeedDelete = TRUE;
1605 Status = BdsLibGetImageHeader (
1606 FileSystemHandles[Index],
1607 EFI_REMOVABLE_MEDIA_FILE_NAME,
1608 &DosHeader,
1609 Hdr
1610 );
1611 if (!EFI_ERROR (Status) &&
1612 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
1613 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1614 NeedDelete = FALSE;
1615 }
1616
1617 if (NeedDelete) {
1618 //
1619 // No such file or the file is not a EFI application, delete this boot option
1620 //
1621 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
1622 } else {
1623 if (NonBlockNumber != 0) {
1624 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);
1625 } else {
1626 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));
1627 }
1628 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
1629 NonBlockNumber++;
1630 }
1631 }
1632
1633 if (NumberFileSystemHandles != 0) {
1634 FreePool (FileSystemHandles);
1635 }
1636
1637 //
1638 // Parse Network Boot Device
1639 //
1640 NumOfLoadFileHandles = 0;
1641 //
1642 // Search Load File protocol for PXE boot option.
1643 //
1644 gBS->LocateHandleBuffer (
1645 ByProtocol,
1646 &gEfiLoadFileProtocolGuid,
1647 NULL,
1648 &NumOfLoadFileHandles,
1649 &LoadFileHandles
1650 );
1651
1652 for (Index = 0; Index < NumOfLoadFileHandles; Index++) {
1653 if (Index != 0) {
1654 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)), Index);
1655 } else {
1656 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)));
1657 }
1658 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);
1659 }
1660
1661 if (NumOfLoadFileHandles != 0) {
1662 FreePool (LoadFileHandles);
1663 }
1664
1665 //
1666 // Check if we have on flash shell
1667 //
1668 gBS->LocateHandleBuffer (
1669 ByProtocol,
1670 &gEfiFirmwareVolume2ProtocolGuid,
1671 NULL,
1672 &FvHandleCount,
1673 &FvHandleBuffer
1674 );
1675 for (Index = 0; Index < FvHandleCount; Index++) {
1676 gBS->HandleProtocol (
1677 FvHandleBuffer[Index],
1678 &gEfiFirmwareVolume2ProtocolGuid,
1679 (VOID **) &Fv
1680 );
1681
1682 Status = Fv->ReadFile (
1683 Fv,
1684 PcdGetPtr(PcdShellFile),
1685 NULL,
1686 &Size,
1687 &Type,
1688 &Attributes,
1689 &AuthenticationStatus
1690 );
1691 if (EFI_ERROR (Status)) {
1692 //
1693 // Skip if no shell file in the FV
1694 //
1695 continue;
1696 }
1697 //
1698 // Build the shell boot option
1699 //
1700 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
1701 }
1702
1703 if (FvHandleCount != 0) {
1704 FreePool (FvHandleBuffer);
1705 }
1706 //
1707 // Make sure every boot only have one time
1708 // boot device enumerate
1709 //
1710 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1711 mEnumBootDevice = TRUE;
1712
1713 return Status;
1714 }
1715
1716 /**
1717 Build the boot option with the handle parsed in
1718
1719 @param Handle The handle which present the device path to create
1720 boot option
1721 @param BdsBootOptionList The header of the link list which indexed all
1722 current boot options
1723 @param String The description of the boot option.
1724
1725 **/
1726 VOID
1727 EFIAPI
1728 BdsLibBuildOptionFromHandle (
1729 IN EFI_HANDLE Handle,
1730 IN LIST_ENTRY *BdsBootOptionList,
1731 IN CHAR16 *String
1732 )
1733 {
1734 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1735
1736 DevicePath = DevicePathFromHandle (Handle);
1737
1738 //
1739 // Create and register new boot option
1740 //
1741 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
1742 }
1743
1744
1745 /**
1746 Build the on flash shell boot option with the handle parsed in.
1747
1748 @param Handle The handle which present the device path to create
1749 on flash shell boot option
1750 @param BdsBootOptionList The header of the link list which indexed all
1751 current boot options
1752
1753 **/
1754 VOID
1755 EFIAPI
1756 BdsLibBuildOptionFromShell (
1757 IN EFI_HANDLE Handle,
1758 IN OUT LIST_ENTRY *BdsBootOptionList
1759 )
1760 {
1761 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1762 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
1763
1764 DevicePath = DevicePathFromHandle (Handle);
1765
1766 //
1767 // Build the shell device path
1768 //
1769 EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
1770
1771 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
1772
1773 //
1774 // Create and register the shell boot option
1775 //
1776 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
1777
1778 }
1779
1780 /**
1781 Boot from the UEFI spec defined "BootNext" variable.
1782
1783 **/
1784 VOID
1785 EFIAPI
1786 BdsLibBootNext (
1787 VOID
1788 )
1789 {
1790 UINT16 *BootNext;
1791 UINTN BootNextSize;
1792 CHAR16 Buffer[20];
1793 BDS_COMMON_OPTION *BootOption;
1794 LIST_ENTRY TempList;
1795 UINTN ExitDataSize;
1796 CHAR16 *ExitData;
1797
1798 //
1799 // Init the boot option name buffer and temp link list
1800 //
1801 InitializeListHead (&TempList);
1802 ZeroMem (Buffer, sizeof (Buffer));
1803
1804 BootNext = BdsLibGetVariableAndSize (
1805 L"BootNext",
1806 &gEfiGlobalVariableGuid,
1807 &BootNextSize
1808 );
1809
1810 //
1811 // Clear the boot next variable first
1812 //
1813 if (BootNext != NULL) {
1814 gRT->SetVariable (
1815 L"BootNext",
1816 &gEfiGlobalVariableGuid,
1817 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1818 0,
1819 BootNext
1820 );
1821
1822 //
1823 // Start to build the boot option and try to boot
1824 //
1825 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
1826 BootOption = BdsLibVariableToOption (&TempList, Buffer);
1827 ASSERT (BootOption != NULL);
1828 BdsLibConnectDevicePath (BootOption->DevicePath);
1829 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
1830 }
1831
1832 }
1833
1834 /**
1835 Return the bootable media handle.
1836 First, check the device is connected
1837 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1838 Third, detect the the default boot file in the Media, and return the removable Media handle.
1839
1840 @param DevicePath Device Path to a bootable device
1841
1842 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
1843
1844 **/
1845 EFI_HANDLE
1846 EFIAPI
1847 BdsLibGetBootableHandle (
1848 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1849 )
1850 {
1851 EFI_STATUS Status;
1852 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1853 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
1854 EFI_HANDLE Handle;
1855 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1856 VOID *Buffer;
1857 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1858 UINTN Size;
1859 UINTN TempSize;
1860 EFI_HANDLE ReturnHandle;
1861 EFI_HANDLE *SimpleFileSystemHandles;
1862
1863 UINTN NumberSimpleFileSystemHandles;
1864 UINTN Index;
1865 EFI_IMAGE_DOS_HEADER DosHeader;
1866 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1867 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1868
1869 UpdatedDevicePath = DevicePath;
1870
1871 //
1872 // Check whether the device is connected
1873 //
1874 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
1875 if (EFI_ERROR (Status)) {
1876 //
1877 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1878 //
1879 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
1880 if (EFI_ERROR (Status)) {
1881 //
1882 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1883 //
1884 UpdatedDevicePath = DevicePath;
1885 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1886 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1887 }
1888 } else {
1889 //
1890 // For removable device boot option, its contained device path only point to the removable device handle,
1891 // should make sure all its children handles (its child partion or media handles) are created and connected.
1892 //
1893 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1894 //
1895 // Get BlockIo protocol and check removable attribute
1896 //
1897 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1898 //
1899 // Issue a dummy read to the device to check for media change.
1900 // When the removable media is changed, any Block IO read/write will
1901 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1902 // returned. After the Block IO protocol is reinstalled, subsequent
1903 // Block IO read/write will success.
1904 //
1905 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1906 if (Buffer != NULL) {
1907 BlockIo->ReadBlocks (
1908 BlockIo,
1909 BlockIo->Media->MediaId,
1910 0,
1911 BlockIo->Media->BlockSize,
1912 Buffer
1913 );
1914 FreePool(Buffer);
1915 }
1916 }
1917
1918 //
1919 // Detect the the default boot file from removable Media
1920 //
1921
1922 //
1923 // 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
1924 // Try to locate the USB node device path first, if fail then use its previous PCI node to search
1925 //
1926 DupDevicePath = DuplicateDevicePath (DevicePath);
1927 ASSERT (DupDevicePath != NULL);
1928
1929 UpdatedDevicePath = DupDevicePath;
1930 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1931 //
1932 // 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
1933 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1934 //
1935 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
1936 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
1937 //
1938 // Remove the usb node, let the device path only point to PCI node
1939 //
1940 SetDevicePathEndNode (UpdatedDevicePath);
1941 UpdatedDevicePath = DupDevicePath;
1942 } else {
1943 UpdatedDevicePath = DevicePath;
1944 }
1945
1946 //
1947 // Get the device path size of boot option
1948 //
1949 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1950 ReturnHandle = NULL;
1951 gBS->LocateHandleBuffer (
1952 ByProtocol,
1953 &gEfiSimpleFileSystemProtocolGuid,
1954 NULL,
1955 &NumberSimpleFileSystemHandles,
1956 &SimpleFileSystemHandles
1957 );
1958 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1959 //
1960 // Get the device path size of SimpleFileSystem handle
1961 //
1962 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1963 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1964 //
1965 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1966 //
1967 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
1968 //
1969 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1970 // machinename is ia32, ia64, x64, ...
1971 //
1972 Hdr.Union = &HdrData;
1973 Status = BdsLibGetImageHeader (
1974 SimpleFileSystemHandles[Index],
1975 EFI_REMOVABLE_MEDIA_FILE_NAME,
1976 &DosHeader,
1977 Hdr
1978 );
1979 if (!EFI_ERROR (Status) &&
1980 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
1981 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1982 ReturnHandle = SimpleFileSystemHandles[Index];
1983 break;
1984 }
1985 }
1986 }
1987
1988 FreePool(DupDevicePath);
1989
1990 if (SimpleFileSystemHandles != NULL) {
1991 FreePool(SimpleFileSystemHandles);
1992 }
1993
1994 return ReturnHandle;
1995 }
1996
1997 /**
1998 Check to see if the network cable is plugged in. If the DevicePath is not
1999 connected it will be connected.
2000
2001 @param DevicePath Device Path to check
2002
2003 @retval TRUE DevicePath points to an Network that is connected
2004 @retval FALSE DevicePath does not point to a bootable network
2005
2006 **/
2007 BOOLEAN
2008 BdsLibNetworkBootWithMediaPresent (
2009 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
2010 )
2011 {
2012 EFI_STATUS Status;
2013 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
2014 EFI_HANDLE Handle;
2015 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
2016 BOOLEAN MediaPresent;
2017 UINT32 InterruptStatus;
2018
2019 MediaPresent = FALSE;
2020
2021 UpdatedDevicePath = DevicePath;
2022 //
2023 // Locate Load File Protocol for PXE boot option first
2024 //
2025 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
2026 if (EFI_ERROR (Status)) {
2027 //
2028 // Device not present so see if we need to connect it
2029 //
2030 Status = BdsLibConnectDevicePath (DevicePath);
2031 if (!EFI_ERROR (Status)) {
2032 //
2033 // This one should work after we did the connect
2034 //
2035 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
2036 }
2037 }
2038
2039 if (!EFI_ERROR (Status)) {
2040 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
2041 if (EFI_ERROR (Status)) {
2042 //
2043 // Failed to open SNP from this handle, try to get SNP from parent handle
2044 //
2045 UpdatedDevicePath = DevicePathFromHandle (Handle);
2046 if (UpdatedDevicePath != NULL) {
2047 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
2048 if (!EFI_ERROR (Status)) {
2049 //
2050 // SNP handle found, get SNP from it
2051 //
2052 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);
2053 }
2054 }
2055 }
2056
2057 if (!EFI_ERROR (Status)) {
2058 if (Snp->Mode->MediaPresentSupported) {
2059 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
2060 //
2061 // Invoke Snp->GetStatus() to refresh the media status
2062 //
2063 Snp->GetStatus (Snp, &InterruptStatus, NULL);
2064
2065 //
2066 // In case some one else is using the SNP check to see if it's connected
2067 //
2068 MediaPresent = Snp->Mode->MediaPresent;
2069 } else {
2070 //
2071 // No one is using SNP so we need to Start and Initialize so
2072 // MediaPresent will be valid.
2073 //
2074 Status = Snp->Start (Snp);
2075 if (!EFI_ERROR (Status)) {
2076 Status = Snp->Initialize (Snp, 0, 0);
2077 if (!EFI_ERROR (Status)) {
2078 MediaPresent = Snp->Mode->MediaPresent;
2079 Snp->Shutdown (Snp);
2080 }
2081 Snp->Stop (Snp);
2082 }
2083 }
2084 } else {
2085 MediaPresent = TRUE;
2086 }
2087 }
2088 }
2089
2090 return MediaPresent;
2091 }
2092
2093 /**
2094 For a bootable Device path, return its boot type.
2095
2096 @param DevicePath The bootable device Path to check
2097
2098 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
2099 which subtype is MEDIA_HARDDRIVE_DP
2100 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
2101 which subtype is MEDIA_CDROM_DP
2102 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
2103 which HID is floppy device.
2104 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
2105 and its last device path node's subtype is MSG_ATAPI_DP.
2106 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
2107 and its last device path node's subtype is MSG_SCSI_DP.
2108 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
2109 and its last device path node's subtype is MSG_USB_DP.
2110 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
2111 its last device path node point to a message device path node.
2112 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
2113 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
2114
2115 **/
2116 UINT32
2117 EFIAPI
2118 BdsGetBootTypeFromDevicePath (
2119 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
2120 )
2121 {
2122 ACPI_HID_DEVICE_PATH *Acpi;
2123 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2124 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
2125 UINT32 BootType;
2126
2127 if (NULL == DevicePath) {
2128 return BDS_EFI_UNSUPPORT;
2129 }
2130
2131 TempDevicePath = DevicePath;
2132
2133 while (!IsDevicePathEndType (TempDevicePath)) {
2134 switch (DevicePathType (TempDevicePath)) {
2135 case BBS_DEVICE_PATH:
2136 return BDS_LEGACY_BBS_BOOT;
2137 case MEDIA_DEVICE_PATH:
2138 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
2139 return BDS_EFI_MEDIA_HD_BOOT;
2140 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
2141 return BDS_EFI_MEDIA_CDROM_BOOT;
2142 }
2143 break;
2144 case ACPI_DEVICE_PATH:
2145 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
2146 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
2147 return BDS_EFI_ACPI_FLOPPY_BOOT;
2148 }
2149 break;
2150 case MESSAGING_DEVICE_PATH:
2151 //
2152 // Get the last device path node
2153 //
2154 LastDeviceNode = NextDevicePathNode (TempDevicePath);
2155 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
2156 //
2157 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
2158 // skip it
2159 //
2160 LastDeviceNode = NextDevicePathNode (LastDeviceNode);
2161 }
2162 //
2163 // if the device path not only point to driver device, it is not a messaging device path,
2164 //
2165 if (!IsDevicePathEndType (LastDeviceNode)) {
2166 break;
2167 }
2168
2169 switch (DevicePathSubType (TempDevicePath)) {
2170 case MSG_ATAPI_DP:
2171 BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
2172 break;
2173
2174 case MSG_USB_DP:
2175 BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
2176 break;
2177
2178 case MSG_SCSI_DP:
2179 BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
2180 break;
2181
2182 case MSG_SATA_DP:
2183 BootType = BDS_EFI_MESSAGE_SATA_BOOT;
2184 break;
2185
2186 case MSG_MAC_ADDR_DP:
2187 case MSG_VLAN_DP:
2188 case MSG_IPv4_DP:
2189 case MSG_IPv6_DP:
2190 BootType = BDS_EFI_MESSAGE_MAC_BOOT;
2191 break;
2192
2193 default:
2194 BootType = BDS_EFI_MESSAGE_MISC_BOOT;
2195 break;
2196 }
2197 return BootType;
2198
2199 default:
2200 break;
2201 }
2202 TempDevicePath = NextDevicePathNode (TempDevicePath);
2203 }
2204
2205 return BDS_EFI_UNSUPPORT;
2206 }
2207
2208 /**
2209 Check whether the Device path in a boot option point to a valid bootable device,
2210 And if CheckMedia is true, check the device is ready to boot now.
2211
2212 @param DevPath the Device path in a boot option
2213 @param CheckMedia if true, check the device is ready to boot now.
2214
2215 @retval TRUE the Device path is valid
2216 @retval FALSE the Device path is invalid .
2217
2218 **/
2219 BOOLEAN
2220 EFIAPI
2221 BdsLibIsValidEFIBootOptDevicePath (
2222 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
2223 IN BOOLEAN CheckMedia
2224 )
2225 {
2226 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
2227 }
2228
2229 /**
2230 Check whether the Device path in a boot option point to a valid bootable device,
2231 And if CheckMedia is true, check the device is ready to boot now.
2232 If Description is not NULL and the device path point to a fixed BlockIo
2233 device, check the description whether conflict with other auto-created
2234 boot options.
2235
2236 @param DevPath the Device path in a boot option
2237 @param CheckMedia if true, check the device is ready to boot now.
2238 @param Description the description in a boot option
2239
2240 @retval TRUE the Device path is valid
2241 @retval FALSE the Device path is invalid .
2242
2243 **/
2244 BOOLEAN
2245 EFIAPI
2246 BdsLibIsValidEFIBootOptDevicePathExt (
2247 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
2248 IN BOOLEAN CheckMedia,
2249 IN CHAR16 *Description
2250 )
2251 {
2252 EFI_STATUS Status;
2253 EFI_HANDLE Handle;
2254 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2255 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
2256 EFI_BLOCK_IO_PROTOCOL *BlockIo;
2257
2258 TempDevicePath = DevPath;
2259 LastDeviceNode = DevPath;
2260
2261 //
2262 // Check if it's a valid boot option for network boot device.
2263 // Check if there is EfiLoadFileProtocol installed.
2264 // If yes, that means there is a boot option for network.
2265 //
2266 Status = gBS->LocateDevicePath (
2267 &gEfiLoadFileProtocolGuid,
2268 &TempDevicePath,
2269 &Handle
2270 );
2271 if (EFI_ERROR (Status)) {
2272 //
2273 // Device not present so see if we need to connect it
2274 //
2275 TempDevicePath = DevPath;
2276 BdsLibConnectDevicePath (TempDevicePath);
2277 Status = gBS->LocateDevicePath (
2278 &gEfiLoadFileProtocolGuid,
2279 &TempDevicePath,
2280 &Handle
2281 );
2282 }
2283
2284 if (!EFI_ERROR (Status)) {
2285 if (!IsDevicePathEnd (TempDevicePath)) {
2286 //
2287 // LoadFile protocol is not installed on handle with exactly the same DevPath
2288 //
2289 return FALSE;
2290 }
2291
2292 if (CheckMedia) {
2293 //
2294 // Test if it is ready to boot now
2295 //
2296 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
2297 return TRUE;
2298 }
2299 } else {
2300 return TRUE;
2301 }
2302 }
2303
2304 //
2305 // If the boot option point to a file, it is a valid EFI boot option,
2306 // and assume it is ready to boot now
2307 //
2308 while (!IsDevicePathEnd (TempDevicePath)) {
2309 //
2310 // If there is USB Class or USB WWID device path node, treat it as valid EFI
2311 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
2312 // to full device path.
2313 //
2314 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
2315 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
2316 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
2317 return TRUE;
2318 }
2319
2320 LastDeviceNode = TempDevicePath;
2321 TempDevicePath = NextDevicePathNode (TempDevicePath);
2322 }
2323 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
2324 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
2325 return TRUE;
2326 }
2327
2328 //
2329 // Check if it's a valid boot option for internal Shell
2330 //
2331 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
2332 //
2333 // If the boot option point to Internal FV shell, make sure it is valid
2334 //
2335 TempDevicePath = DevPath;
2336 Status = BdsLibUpdateFvFileDevicePath (&TempDevicePath, PcdGetPtr(PcdShellFile));
2337 if (Status == EFI_ALREADY_STARTED) {
2338 return TRUE;
2339 } else {
2340 if (Status == EFI_SUCCESS) {
2341 FreePool (TempDevicePath);
2342 }
2343 return FALSE;
2344 }
2345 }
2346
2347 //
2348 // If the boot option point to a blockIO device:
2349 // if it is a removable blockIo device, it is valid.
2350 // if it is a fixed blockIo device, check its description confliction.
2351 //
2352 TempDevicePath = DevPath;
2353 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
2354 if (EFI_ERROR (Status)) {
2355 //
2356 // Device not present so see if we need to connect it
2357 //
2358 Status = BdsLibConnectDevicePath (DevPath);
2359 if (!EFI_ERROR (Status)) {
2360 //
2361 // Try again to get the Block Io protocol after we did the connect
2362 //
2363 TempDevicePath = DevPath;
2364 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
2365 }
2366 }
2367
2368 if (!EFI_ERROR (Status)) {
2369 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
2370 if (!EFI_ERROR (Status)) {
2371 if (CheckMedia) {
2372 //
2373 // Test if it is ready to boot now
2374 //
2375 if (BdsLibGetBootableHandle (DevPath) != NULL) {
2376 return TRUE;
2377 }
2378 } else {
2379 return TRUE;
2380 }
2381 }
2382 } else {
2383 //
2384 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
2385 //
2386 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
2387 if (!EFI_ERROR (Status)) {
2388 if (CheckMedia) {
2389 //
2390 // Test if it is ready to boot now
2391 //
2392 if (BdsLibGetBootableHandle (DevPath) != NULL) {
2393 return TRUE;
2394 }
2395 } else {
2396 return TRUE;
2397 }
2398 }
2399 }
2400
2401 return FALSE;
2402 }
2403
2404
2405 /**
2406 According to a file guild, check a Fv file device path is valid. If it is invalid,
2407 try to return the valid device path.
2408 FV address maybe changes for memory layout adjust from time to time, use this function
2409 could promise the Fv file device path is right.
2410
2411 @param DevicePath on input, the Fv file device path need to check on
2412 output, the updated valid Fv file device path
2413 @param FileGuid the Fv file guild
2414
2415 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
2416 parameter
2417 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
2418 guild at all
2419 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
2420 valid
2421 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
2422 and return the updated device path in DevicePath
2423
2424 **/
2425 EFI_STATUS
2426 EFIAPI
2427 BdsLibUpdateFvFileDevicePath (
2428 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
2429 IN EFI_GUID *FileGuid
2430 )
2431 {
2432 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2433 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
2434 EFI_STATUS Status;
2435 EFI_GUID *GuidPoint;
2436 UINTN Index;
2437 UINTN FvHandleCount;
2438 EFI_HANDLE *FvHandleBuffer;
2439 EFI_FV_FILETYPE Type;
2440 UINTN Size;
2441 EFI_FV_FILE_ATTRIBUTES Attributes;
2442 UINT32 AuthenticationStatus;
2443 BOOLEAN FindFvFile;
2444 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2445 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
2446 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
2447 EFI_HANDLE FoundFvHandle;
2448 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
2449
2450 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
2451 return EFI_INVALID_PARAMETER;
2452 }
2453 if (FileGuid == NULL) {
2454 return EFI_INVALID_PARAMETER;
2455 }
2456
2457 //
2458 // Check whether the device path point to the default the input Fv file
2459 //
2460 TempDevicePath = *DevicePath;
2461 LastDeviceNode = TempDevicePath;
2462 while (!IsDevicePathEnd (TempDevicePath)) {
2463 LastDeviceNode = TempDevicePath;
2464 TempDevicePath = NextDevicePathNode (TempDevicePath);
2465 }
2466 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
2467 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
2468 );
2469 if (GuidPoint == NULL) {
2470 //
2471 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
2472 //
2473 return EFI_UNSUPPORTED;
2474 }
2475 if (!CompareGuid (GuidPoint, FileGuid)) {
2476 //
2477 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
2478 //
2479 return EFI_UNSUPPORTED;
2480 }
2481
2482 //
2483 // Check whether the input Fv file device path is valid
2484 //
2485 TempDevicePath = *DevicePath;
2486 FoundFvHandle = NULL;
2487 Status = gBS->LocateDevicePath (
2488 &gEfiFirmwareVolume2ProtocolGuid,
2489 &TempDevicePath,
2490 &FoundFvHandle
2491 );
2492 if (!EFI_ERROR (Status)) {
2493 Status = gBS->HandleProtocol (
2494 FoundFvHandle,
2495 &gEfiFirmwareVolume2ProtocolGuid,
2496 (VOID **) &Fv
2497 );
2498 if (!EFI_ERROR (Status)) {
2499 //
2500 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
2501 //
2502 Status = Fv->ReadFile (
2503 Fv,
2504 FileGuid,
2505 NULL,
2506 &Size,
2507 &Type,
2508 &Attributes,
2509 &AuthenticationStatus
2510 );
2511 if (!EFI_ERROR (Status)) {
2512 return EFI_ALREADY_STARTED;
2513 }
2514 }
2515 }
2516
2517 //
2518 // Look for the input wanted FV file in current FV
2519 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
2520 //
2521 FindFvFile = FALSE;
2522 FoundFvHandle = NULL;
2523 Status = gBS->HandleProtocol (
2524 gImageHandle,
2525 &gEfiLoadedImageProtocolGuid,
2526 (VOID **) &LoadedImage
2527 );
2528 if (!EFI_ERROR (Status)) {
2529 Status = gBS->HandleProtocol (
2530 LoadedImage->DeviceHandle,
2531 &gEfiFirmwareVolume2ProtocolGuid,
2532 (VOID **) &Fv
2533 );
2534 if (!EFI_ERROR (Status)) {
2535 Status = Fv->ReadFile (
2536 Fv,
2537 FileGuid,
2538 NULL,
2539 &Size,
2540 &Type,
2541 &Attributes,
2542 &AuthenticationStatus
2543 );
2544 if (!EFI_ERROR (Status)) {
2545 FindFvFile = TRUE;
2546 FoundFvHandle = LoadedImage->DeviceHandle;
2547 }
2548 }
2549 }
2550 //
2551 // Second, if fail to find, try to enumerate all FV
2552 //
2553 if (!FindFvFile) {
2554 FvHandleBuffer = NULL;
2555 gBS->LocateHandleBuffer (
2556 ByProtocol,
2557 &gEfiFirmwareVolume2ProtocolGuid,
2558 NULL,
2559 &FvHandleCount,
2560 &FvHandleBuffer
2561 );
2562 for (Index = 0; Index < FvHandleCount; Index++) {
2563 gBS->HandleProtocol (
2564 FvHandleBuffer[Index],
2565 &gEfiFirmwareVolume2ProtocolGuid,
2566 (VOID **) &Fv
2567 );
2568
2569 Status = Fv->ReadFile (
2570 Fv,
2571 FileGuid,
2572 NULL,
2573 &Size,
2574 &Type,
2575 &Attributes,
2576 &AuthenticationStatus
2577 );
2578 if (EFI_ERROR (Status)) {
2579 //
2580 // Skip if input Fv file not in the FV
2581 //
2582 continue;
2583 }
2584 FindFvFile = TRUE;
2585 FoundFvHandle = FvHandleBuffer[Index];
2586 break;
2587 }
2588
2589 if (FvHandleBuffer != NULL) {
2590 FreePool (FvHandleBuffer);
2591 }
2592 }
2593
2594 if (FindFvFile) {
2595 //
2596 // Build the shell device path
2597 //
2598 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
2599 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
2600 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
2601 *DevicePath = NewDevicePath;
2602 return EFI_SUCCESS;
2603 }
2604 return EFI_NOT_FOUND;
2605 }