]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Bds: Support booting from remote file system.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBoot.c
1 /** @file
2 Library functions which relates with booting.
3
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "InternalBm.h"
17
18 #define VENDOR_IDENTIFICATION_OFFSET 3
19 #define VENDOR_IDENTIFICATION_LENGTH 8
20 #define PRODUCT_IDENTIFICATION_OFFSET 11
21 #define PRODUCT_IDENTIFICATION_LENGTH 16
22
23 CONST UINT16 mBmUsbLangId = 0x0409; // English
24 CHAR16 mBmUefiPrefix[] = L"UEFI ";
25
26 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
27 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;
28
29 LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
30
31 ///
32 /// This GUID is used for an EFI Variable that stores the front device pathes
33 /// for a partial device path that starts with the HD node.
34 ///
35 EFI_GUID mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
36 EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
37
38 /**
39 The function registers the legacy boot support capabilities.
40
41 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
42 @param LegacyBoot The function pointer to boot the legacy boot option.
43 **/
44 VOID
45 EFIAPI
46 EfiBootManagerRegisterLegacyBootSupport (
47 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
48 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
49 )
50 {
51 mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
52 mBmLegacyBoot = LegacyBoot;
53 }
54
55 /**
56 Return TRUE when the boot option is auto-created instead of manually added.
57
58 @param BootOption Pointer to the boot option to check.
59
60 @retval TRUE The boot option is auto-created.
61 @retval FALSE The boot option is manually added.
62 **/
63 BOOLEAN
64 BmIsAutoCreateBootOption (
65 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
66 )
67 {
68 if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
69 CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
70 ) {
71 return TRUE;
72 } else {
73 return FALSE;
74 }
75 }
76
77 /**
78 For a bootable Device path, return its boot type.
79
80 @param DevicePath The bootable device Path to check
81
82 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
83 which HID is floppy device.
84 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
85 and its last device path node's subtype is MSG_ATAPI_DP.
86 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
87 and its last device path node's subtype is MSG_SATA_DP.
88 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
89 and its last device path node's subtype is MSG_SCSI_DP.
90 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
91 and its last device path node's subtype is MSG_USB_DP.
92 @retval MessageNetworkBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
93 and its last device path node's subtype is MSG_MAC_ADDR_DP, MSG_VLAN_DP,
94 MSG_IPv4_DP or MSG_IPv6_DP.
95 @retval MessageHttpBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
96 and its last device path node's subtype is MSG_URI_DP.
97 @retval UnsupportedBoot If tiven device path doesn't match the above condition, it's not supported.
98
99 **/
100 BM_BOOT_TYPE
101 BmDevicePathType (
102 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
103 )
104 {
105 EFI_DEVICE_PATH_PROTOCOL *Node;
106 EFI_DEVICE_PATH_PROTOCOL *NextNode;
107
108 ASSERT (DevicePath != NULL);
109
110 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
111 switch (DevicePathType (Node)) {
112
113 case ACPI_DEVICE_PATH:
114 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
115 return BmAcpiFloppyBoot;
116 }
117 break;
118
119 case HARDWARE_DEVICE_PATH:
120 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
121 return BmHardwareDeviceBoot;
122 }
123 break;
124
125 case MESSAGING_DEVICE_PATH:
126 //
127 // Skip LUN device node
128 //
129 NextNode = Node;
130 do {
131 NextNode = NextDevicePathNode (NextNode);
132 } while (
133 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
134 (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
135 );
136
137 //
138 // If the device path not only point to driver device, it is not a messaging device path,
139 //
140 if (!IsDevicePathEndType (NextNode)) {
141 continue;
142 }
143
144 switch (DevicePathSubType (Node)) {
145 case MSG_ATAPI_DP:
146 return BmMessageAtapiBoot;
147 break;
148
149 case MSG_SATA_DP:
150 return BmMessageSataBoot;
151 break;
152
153 case MSG_USB_DP:
154 return BmMessageUsbBoot;
155 break;
156
157 case MSG_SCSI_DP:
158 return BmMessageScsiBoot;
159 break;
160
161 case MSG_MAC_ADDR_DP:
162 case MSG_VLAN_DP:
163 case MSG_IPv4_DP:
164 case MSG_IPv6_DP:
165 return BmMessageNetworkBoot;
166 break;
167
168 case MSG_URI_DP:
169 return BmMessageHttpBoot;
170 break;
171 }
172 }
173 }
174
175 return BmMiscBoot;
176 }
177
178 /**
179 Find the boot option in the NV storage and return the option number.
180
181 @param OptionToFind Boot option to be checked.
182
183 @return The option number of the found boot option.
184
185 **/
186 UINTN
187 BmFindBootOptionInVariable (
188 IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind
189 )
190 {
191 EFI_STATUS Status;
192 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
193 UINTN OptionNumber;
194 CHAR16 OptionName[BM_OPTION_NAME_LEN];
195 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
196 UINTN BootOptionCount;
197 UINTN Index;
198
199 OptionNumber = LoadOptionNumberUnassigned;
200
201 //
202 // Try to match the variable exactly if the option number is assigned
203 //
204 if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
205 UnicodeSPrint (
206 OptionName, sizeof (OptionName), L"%s%04x",
207 mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
208 );
209 Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
210
211 if (!EFI_ERROR (Status)) {
212 ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
213 if ((OptionToFind->Attributes == BootOption.Attributes) &&
214 (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
215 (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
216 (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
217 (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
218 ) {
219 OptionNumber = OptionToFind->OptionNumber;
220 }
221 EfiBootManagerFreeLoadOption (&BootOption);
222 }
223 }
224
225 //
226 // The option number assigned is either incorrect or unassigned.
227 //
228 if (OptionNumber == LoadOptionNumberUnassigned) {
229 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
230
231 Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
232 if (Index != -1) {
233 OptionNumber = BootOptions[Index].OptionNumber;
234 }
235
236 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
237 }
238
239 return OptionNumber;
240 }
241
242 /**
243 Get the file buffer using a Memory Mapped Device Path.
244
245 FV address may change across reboot. This routine promises the FV file device path is right.
246
247 @param FilePath The Memory Mapped Device Path to get the file buffer.
248 @param FullPath Receive the updated FV Device Path pointint to the file.
249 @param FileSize Receive the file buffer size.
250
251 @return The file buffer.
252 **/
253 VOID *
254 BmGetFileBufferByFvFilePath (
255 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
256 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
257 OUT UINTN *FileSize
258 )
259 {
260 EFI_STATUS Status;
261 UINTN Index;
262 EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
263 EFI_HANDLE FvHandle;
264 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
265 UINT32 AuthenticationStatus;
266 UINTN FvHandleCount;
267 EFI_HANDLE *FvHandles;
268 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
269 VOID *FileBuffer;
270
271 //
272 // Get the file buffer by using the exactly FilePath.
273 //
274 FvFileNode = FilePath;
275 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
276 if (!EFI_ERROR (Status)) {
277 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
278 if (FileBuffer != NULL) {
279 *FullPath = DuplicateDevicePath (FilePath);
280 }
281 return FileBuffer;
282 }
283
284 //
285 // Only wide match other FVs if it's a memory mapped FV file path.
286 //
287 if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {
288 return NULL;
289 }
290
291 FvFileNode = NextDevicePathNode (FilePath);
292
293 //
294 // Firstly find the FV file in current FV
295 //
296 gBS->HandleProtocol (
297 gImageHandle,
298 &gEfiLoadedImageProtocolGuid,
299 (VOID **) &LoadedImage
300 );
301 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
302 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
303 FreePool (NewDevicePath);
304
305 if (FileBuffer != NULL) {
306 return FileBuffer;
307 }
308
309 //
310 // Secondly find the FV file in all other FVs
311 //
312 gBS->LocateHandleBuffer (
313 ByProtocol,
314 &gEfiFirmwareVolume2ProtocolGuid,
315 NULL,
316 &FvHandleCount,
317 &FvHandles
318 );
319 for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
320 if (FvHandles[Index] == LoadedImage->DeviceHandle) {
321 //
322 // Skip current FV
323 //
324 continue;
325 }
326 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
327 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
328 FreePool (NewDevicePath);
329 }
330
331 if (FvHandles != NULL) {
332 FreePool (FvHandles);
333 }
334 return FileBuffer;
335 }
336
337 /**
338 Check if it's a Device Path pointing to FV file.
339
340 The function doesn't garentee the device path points to existing FV file.
341
342 @param DevicePath Input device path.
343
344 @retval TRUE The device path is a FV File Device Path.
345 @retval FALSE The device path is NOT a FV File Device Path.
346 **/
347 BOOLEAN
348 BmIsFvFilePath (
349 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
350 )
351 {
352 EFI_STATUS Status;
353 EFI_HANDLE Handle;
354 EFI_DEVICE_PATH_PROTOCOL *Node;
355
356 Node = DevicePath;
357 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);
358 if (!EFI_ERROR (Status)) {
359 return TRUE;
360 }
361
362 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
363 DevicePath = NextDevicePathNode (DevicePath);
364 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
365 return IsDevicePathEnd (NextDevicePathNode (DevicePath));
366 }
367 }
368 return FALSE;
369 }
370
371 /**
372 Check whether a USB device match the specified USB Class device path. This
373 function follows "Load Option Processing" behavior in UEFI specification.
374
375 @param UsbIo USB I/O protocol associated with the USB device.
376 @param UsbClass The USB Class device path to match.
377
378 @retval TRUE The USB device match the USB Class device path.
379 @retval FALSE The USB device does not match the USB Class device path.
380
381 **/
382 BOOLEAN
383 BmMatchUsbClass (
384 IN EFI_USB_IO_PROTOCOL *UsbIo,
385 IN USB_CLASS_DEVICE_PATH *UsbClass
386 )
387 {
388 EFI_STATUS Status;
389 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
390 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
391 UINT8 DeviceClass;
392 UINT8 DeviceSubClass;
393 UINT8 DeviceProtocol;
394
395 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
396 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
397 return FALSE;
398 }
399
400 //
401 // Check Vendor Id and Product Id.
402 //
403 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
404 if (EFI_ERROR (Status)) {
405 return FALSE;
406 }
407
408 if ((UsbClass->VendorId != 0xffff) &&
409 (UsbClass->VendorId != DevDesc.IdVendor)) {
410 return FALSE;
411 }
412
413 if ((UsbClass->ProductId != 0xffff) &&
414 (UsbClass->ProductId != DevDesc.IdProduct)) {
415 return FALSE;
416 }
417
418 DeviceClass = DevDesc.DeviceClass;
419 DeviceSubClass = DevDesc.DeviceSubClass;
420 DeviceProtocol = DevDesc.DeviceProtocol;
421 if (DeviceClass == 0) {
422 //
423 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
424 // Protocol in Interface Descriptor instead.
425 //
426 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
427 if (EFI_ERROR (Status)) {
428 return FALSE;
429 }
430
431 DeviceClass = IfDesc.InterfaceClass;
432 DeviceSubClass = IfDesc.InterfaceSubClass;
433 DeviceProtocol = IfDesc.InterfaceProtocol;
434 }
435
436 //
437 // Check Class, SubClass and Protocol.
438 //
439 if ((UsbClass->DeviceClass != 0xff) &&
440 (UsbClass->DeviceClass != DeviceClass)) {
441 return FALSE;
442 }
443
444 if ((UsbClass->DeviceSubClass != 0xff) &&
445 (UsbClass->DeviceSubClass != DeviceSubClass)) {
446 return FALSE;
447 }
448
449 if ((UsbClass->DeviceProtocol != 0xff) &&
450 (UsbClass->DeviceProtocol != DeviceProtocol)) {
451 return FALSE;
452 }
453
454 return TRUE;
455 }
456
457 /**
458 Eliminate the extra spaces in the Str to one space.
459
460 @param Str Input string info.
461 **/
462 VOID
463 BmEliminateExtraSpaces (
464 IN CHAR16 *Str
465 )
466 {
467 UINTN Index;
468 UINTN ActualIndex;
469
470 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
471 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
472 Str[ActualIndex++] = Str[Index];
473 }
474 }
475 Str[ActualIndex] = L'\0';
476 }
477
478 /**
479 Try to get the controller's ATA/ATAPI description.
480
481 @param Handle Controller handle.
482
483 @return The description string.
484 **/
485 CHAR16 *
486 BmGetDescriptionFromDiskInfo (
487 IN EFI_HANDLE Handle
488 )
489 {
490 UINTN Index;
491 EFI_STATUS Status;
492 EFI_DISK_INFO_PROTOCOL *DiskInfo;
493 UINT32 BufferSize;
494 EFI_ATAPI_IDENTIFY_DATA IdentifyData;
495 EFI_SCSI_INQUIRY_DATA InquiryData;
496 CHAR16 *Description;
497 UINTN Length;
498 CONST UINTN ModelNameLength = 40;
499 CONST UINTN SerialNumberLength = 20;
500 CHAR8 *StrPtr;
501 UINT8 Temp;
502
503 Description = NULL;
504
505 Status = gBS->HandleProtocol (
506 Handle,
507 &gEfiDiskInfoProtocolGuid,
508 (VOID **) &DiskInfo
509 );
510 if (EFI_ERROR (Status)) {
511 return NULL;
512 }
513
514 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
515 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
516 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
517 Status = DiskInfo->Identify (
518 DiskInfo,
519 &IdentifyData,
520 &BufferSize
521 );
522 if (!EFI_ERROR (Status)) {
523 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
524 ASSERT (Description != NULL);
525 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
526 Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];
527 Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
528 }
529
530 Length = Index;
531 Description[Length++] = L' ';
532
533 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
534 Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];
535 Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
536 }
537 Length += Index;
538 Description[Length++] = L'\0';
539 ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
540
541 BmEliminateExtraSpaces (Description);
542 }
543 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
544 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
545 Status = DiskInfo->Inquiry (
546 DiskInfo,
547 &InquiryData,
548 &BufferSize
549 );
550 if (!EFI_ERROR (Status)) {
551 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
552 ASSERT (Description != NULL);
553
554 //
555 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
556 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
557 // Here combine the vendor identification and product identification to the description.
558 //
559 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
560 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
561 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
562 AsciiStrToUnicodeStr (StrPtr, Description);
563 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
564
565 //
566 // Add one space at the middle of vendor information and product information.
567 //
568 Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
569
570 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
571 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
572 AsciiStrToUnicodeStr (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1);
573
574 BmEliminateExtraSpaces (Description);
575 }
576 }
577
578 return Description;
579 }
580
581 /**
582 Try to get the controller's USB description.
583
584 @param Handle Controller handle.
585
586 @return The description string.
587 **/
588 CHAR16 *
589 BmGetUsbDescription (
590 IN EFI_HANDLE Handle
591 )
592 {
593 EFI_STATUS Status;
594 EFI_USB_IO_PROTOCOL *UsbIo;
595 CHAR16 NullChar;
596 CHAR16 *Manufacturer;
597 CHAR16 *Product;
598 CHAR16 *SerialNumber;
599 CHAR16 *Description;
600 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
601 UINTN DescMaxSize;
602
603 Status = gBS->HandleProtocol (
604 Handle,
605 &gEfiUsbIoProtocolGuid,
606 (VOID **) &UsbIo
607 );
608 if (EFI_ERROR (Status)) {
609 return NULL;
610 }
611
612 NullChar = L'\0';
613
614 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
615 if (EFI_ERROR (Status)) {
616 return NULL;
617 }
618
619 Status = UsbIo->UsbGetStringDescriptor (
620 UsbIo,
621 mBmUsbLangId,
622 DevDesc.StrManufacturer,
623 &Manufacturer
624 );
625 if (EFI_ERROR (Status)) {
626 Manufacturer = &NullChar;
627 }
628
629 Status = UsbIo->UsbGetStringDescriptor (
630 UsbIo,
631 mBmUsbLangId,
632 DevDesc.StrProduct,
633 &Product
634 );
635 if (EFI_ERROR (Status)) {
636 Product = &NullChar;
637 }
638
639 Status = UsbIo->UsbGetStringDescriptor (
640 UsbIo,
641 mBmUsbLangId,
642 DevDesc.StrSerialNumber,
643 &SerialNumber
644 );
645 if (EFI_ERROR (Status)) {
646 SerialNumber = &NullChar;
647 }
648
649 if ((Manufacturer == &NullChar) &&
650 (Product == &NullChar) &&
651 (SerialNumber == &NullChar)
652 ) {
653 return NULL;
654 }
655
656 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
657 Description = AllocateZeroPool (DescMaxSize);
658 ASSERT (Description != NULL);
659 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);
660 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
661
662 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product);
663 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
664
665 StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);
666
667 if (Manufacturer != &NullChar) {
668 FreePool (Manufacturer);
669 }
670 if (Product != &NullChar) {
671 FreePool (Product);
672 }
673 if (SerialNumber != &NullChar) {
674 FreePool (SerialNumber);
675 }
676
677 BmEliminateExtraSpaces (Description);
678
679 return Description;
680 }
681
682 /**
683 Return the boot description for the controller based on the type.
684
685 @param Handle Controller handle.
686
687 @return The description string.
688 **/
689 CHAR16 *
690 BmGetMiscDescription (
691 IN EFI_HANDLE Handle
692 )
693 {
694 EFI_STATUS Status;
695 CHAR16 *Description;
696 EFI_BLOCK_IO_PROTOCOL *BlockIo;
697 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
698
699 switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
700 case BmAcpiFloppyBoot:
701 Description = L"Floppy";
702 break;
703
704 case BmMessageAtapiBoot:
705 case BmMessageSataBoot:
706 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
707 ASSERT_EFI_ERROR (Status);
708 //
709 // Assume a removable SATA device should be the DVD/CD device
710 //
711 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
712 break;
713
714 case BmMessageUsbBoot:
715 Description = L"USB Device";
716 break;
717
718 case BmMessageScsiBoot:
719 Description = L"SCSI Device";
720 break;
721
722 case BmHardwareDeviceBoot:
723 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
724 if (!EFI_ERROR (Status)) {
725 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
726 } else {
727 Description = L"Misc Device";
728 }
729 break;
730
731 case BmMessageNetworkBoot:
732 Description = L"Network";
733 break;
734
735 case BmMessageHttpBoot:
736 Description = L"Http";
737 break;
738
739 default:
740 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);
741 if (!EFI_ERROR (Status)) {
742 Description = L"Non-Block Boot Device";
743 } else {
744 Description = L"Misc Device";
745 }
746 break;
747 }
748
749 return AllocateCopyPool (StrSize (Description), Description);
750 }
751
752 /**
753 Register the platform provided boot description handler.
754
755 @param Handler The platform provided boot description handler
756
757 @retval EFI_SUCCESS The handler was registered successfully.
758 @retval EFI_ALREADY_STARTED The handler was already registered.
759 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
760 **/
761 EFI_STATUS
762 EFIAPI
763 EfiBootManagerRegisterBootDescriptionHandler (
764 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
765 )
766 {
767 LIST_ENTRY *Link;
768 BM_BOOT_DESCRIPTION_ENTRY *Entry;
769
770 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
771 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
772 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
773 ) {
774 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
775 if (Entry->Handler == Handler) {
776 return EFI_ALREADY_STARTED;
777 }
778 }
779
780 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
781 if (Entry == NULL) {
782 return EFI_OUT_OF_RESOURCES;
783 }
784
785 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
786 Entry->Handler = Handler;
787 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
788 return EFI_SUCCESS;
789 }
790
791 BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
792 BmGetUsbDescription,
793 BmGetDescriptionFromDiskInfo,
794 BmGetMiscDescription
795 };
796
797 /**
798 Return the boot description for the controller.
799
800 @param Handle Controller handle.
801
802 @return The description string.
803 **/
804 CHAR16 *
805 BmGetBootDescription (
806 IN EFI_HANDLE Handle
807 )
808 {
809 LIST_ENTRY *Link;
810 BM_BOOT_DESCRIPTION_ENTRY *Entry;
811 CHAR16 *Description;
812 CHAR16 *DefaultDescription;
813 CHAR16 *Temp;
814 UINTN Index;
815
816 //
817 // Firstly get the default boot description
818 //
819 DefaultDescription = NULL;
820 for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {
821 DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);
822 if (DefaultDescription != NULL) {
823 //
824 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
825 // ONLY for core provided boot description handler.
826 //
827 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
828 ASSERT (Temp != NULL);
829 StrCpyS ( Temp,
830 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16),
831 mBmUefiPrefix
832 );
833 StrCatS ( Temp,
834 (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix))/sizeof(CHAR16),
835 DefaultDescription
836 );
837 FreePool (DefaultDescription);
838 DefaultDescription = Temp;
839 break;
840 }
841 }
842 ASSERT (DefaultDescription != NULL);
843
844 //
845 // Secondly query platform for the better boot description
846 //
847 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
848 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
849 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
850 ) {
851 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
852 Description = Entry->Handler (Handle, DefaultDescription);
853 if (Description != NULL) {
854 FreePool (DefaultDescription);
855 return Description;
856 }
857 }
858
859 return DefaultDescription;
860 }
861
862 /**
863 Check whether a USB device match the specified USB WWID device path. This
864 function follows "Load Option Processing" behavior in UEFI specification.
865
866 @param UsbIo USB I/O protocol associated with the USB device.
867 @param UsbWwid The USB WWID device path to match.
868
869 @retval TRUE The USB device match the USB WWID device path.
870 @retval FALSE The USB device does not match the USB WWID device path.
871
872 **/
873 BOOLEAN
874 BmMatchUsbWwid (
875 IN EFI_USB_IO_PROTOCOL *UsbIo,
876 IN USB_WWID_DEVICE_PATH *UsbWwid
877 )
878 {
879 EFI_STATUS Status;
880 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
881 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
882 UINT16 *LangIdTable;
883 UINT16 TableSize;
884 UINT16 Index;
885 CHAR16 *CompareStr;
886 UINTN CompareLen;
887 CHAR16 *SerialNumberStr;
888 UINTN Length;
889
890 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
891 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
892 return FALSE;
893 }
894
895 //
896 // Check Vendor Id and Product Id.
897 //
898 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
899 if (EFI_ERROR (Status)) {
900 return FALSE;
901 }
902 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
903 (DevDesc.IdProduct != UsbWwid->ProductId)) {
904 return FALSE;
905 }
906
907 //
908 // Check Interface Number.
909 //
910 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
911 if (EFI_ERROR (Status)) {
912 return FALSE;
913 }
914 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
915 return FALSE;
916 }
917
918 //
919 // Check Serial Number.
920 //
921 if (DevDesc.StrSerialNumber == 0) {
922 return FALSE;
923 }
924
925 //
926 // Get all supported languages.
927 //
928 TableSize = 0;
929 LangIdTable = NULL;
930 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
931 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
932 return FALSE;
933 }
934
935 //
936 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
937 //
938 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
939 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
940 if (CompareStr[CompareLen - 1] == L'\0') {
941 CompareLen--;
942 }
943
944 //
945 // Compare serial number in each supported language.
946 //
947 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
948 SerialNumberStr = NULL;
949 Status = UsbIo->UsbGetStringDescriptor (
950 UsbIo,
951 LangIdTable[Index],
952 DevDesc.StrSerialNumber,
953 &SerialNumberStr
954 );
955 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
956 continue;
957 }
958
959 Length = StrLen (SerialNumberStr);
960 if ((Length >= CompareLen) &&
961 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
962 FreePool (SerialNumberStr);
963 return TRUE;
964 }
965
966 FreePool (SerialNumberStr);
967 }
968
969 return FALSE;
970 }
971
972 /**
973 Find a USB device which match the specified short-form device path start with
974 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
975 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
976 this function will only search in its child devices.
977
978 @param DevicePath The device path that contains USB Class or USB WWID device path.
979 @param ParentDevicePathSize The length of the device path before the USB Class or
980 USB WWID device path.
981 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
982
983 @retval NULL The matched USB IO handles cannot be found.
984 @retval other The matched USB IO handles.
985
986 **/
987 EFI_HANDLE *
988 BmFindUsbDevice (
989 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
990 IN UINTN ParentDevicePathSize,
991 OUT UINTN *UsbIoHandleCount
992 )
993 {
994 EFI_STATUS Status;
995 EFI_HANDLE *UsbIoHandles;
996 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
997 EFI_USB_IO_PROTOCOL *UsbIo;
998 UINTN Index;
999 BOOLEAN Matched;
1000
1001 ASSERT (UsbIoHandleCount != NULL);
1002
1003 //
1004 // Get all UsbIo Handles.
1005 //
1006 Status = gBS->LocateHandleBuffer (
1007 ByProtocol,
1008 &gEfiUsbIoProtocolGuid,
1009 NULL,
1010 UsbIoHandleCount,
1011 &UsbIoHandles
1012 );
1013 if (EFI_ERROR (Status)) {
1014 *UsbIoHandleCount = 0;
1015 UsbIoHandles = NULL;
1016 }
1017
1018 for (Index = 0; Index < *UsbIoHandleCount; ) {
1019 //
1020 // Get the Usb IO interface.
1021 //
1022 Status = gBS->HandleProtocol(
1023 UsbIoHandles[Index],
1024 &gEfiUsbIoProtocolGuid,
1025 (VOID **) &UsbIo
1026 );
1027 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
1028 Matched = FALSE;
1029 if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
1030
1031 //
1032 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
1033 //
1034 if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
1035 if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
1036 BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
1037 Matched = TRUE;
1038 }
1039 }
1040 }
1041
1042 if (!Matched) {
1043 (*UsbIoHandleCount) --;
1044 CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
1045 } else {
1046 Index++;
1047 }
1048 }
1049
1050 return UsbIoHandles;
1051 }
1052
1053 /**
1054 Expand USB Class or USB WWID device path node to be full device path of a USB
1055 device in platform.
1056
1057 This function support following 4 cases:
1058 1) Boot Option device path starts with a USB Class or USB WWID device path,
1059 and there is no Media FilePath device path in the end.
1060 In this case, it will follow Removable Media Boot Behavior.
1061 2) Boot Option device path starts with a USB Class or USB WWID device path,
1062 and ended with Media FilePath device path.
1063 3) Boot Option device path starts with a full device path to a USB Host Controller,
1064 contains a USB Class or USB WWID device path node, while not ended with Media
1065 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
1066 4) Boot Option device path starts with a full device path to a USB Host Controller,
1067 contains a USB Class or USB WWID device path node, and ended with Media
1068 FilePath device path.
1069
1070 @param FilePath The device path pointing to a load option.
1071 It could be a short-form device path.
1072 @param FullPath Return the full device path of the load option after
1073 short-form device path expanding.
1074 Caller is responsible to free it.
1075 @param FileSize Return the load option size.
1076 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
1077
1078 @return The load option buffer. Caller is responsible to free the memory.
1079 **/
1080 VOID *
1081 BmExpandUsbDevicePath (
1082 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1083 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1084 OUT UINTN *FileSize,
1085 IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
1086 )
1087 {
1088 UINTN ParentDevicePathSize;
1089 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
1090 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
1091 EFI_HANDLE *Handles;
1092 UINTN HandleCount;
1093 UINTN Index;
1094 VOID *FileBuffer;
1095
1096 ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
1097 RemainingDevicePath = NextDevicePathNode (ShortformNode);
1098 FileBuffer = NULL;
1099 Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
1100
1101 for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
1102 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
1103 FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
1104 FreePool (FullDevicePath);
1105 }
1106
1107 if (Handles != NULL) {
1108 FreePool (Handles);
1109 }
1110
1111 return FileBuffer;
1112 }
1113
1114 /**
1115 Expand File-path device path node to be full device path in platform.
1116
1117 @param FilePath The device path pointing to a load option.
1118 It could be a short-form device path.
1119 @param FullPath Return the full device path of the load option after
1120 short-form device path expanding.
1121 Caller is responsible to free it.
1122 @param FileSize Return the load option size.
1123
1124 @return The load option buffer. Caller is responsible to free the memory.
1125 **/
1126 VOID *
1127 BmExpandFileDevicePath (
1128 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1129 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1130 OUT UINTN *FileSize
1131 )
1132 {
1133 EFI_STATUS Status;
1134 UINTN Index;
1135 UINTN HandleCount;
1136 EFI_HANDLE *Handles;
1137 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1138 UINTN MediaType;
1139 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
1140 VOID *FileBuffer;
1141 UINT32 AuthenticationStatus;
1142
1143 EfiBootManagerConnectAll ();
1144 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
1145 if (EFI_ERROR (Status)) {
1146 HandleCount = 0;
1147 Handles = NULL;
1148 }
1149
1150 //
1151 // Enumerate all removable media devices followed by all fixed media devices,
1152 // followed by media devices which don't layer on block io.
1153 //
1154 for (MediaType = 0; MediaType < 3; MediaType++) {
1155 for (Index = 0; Index < HandleCount; Index++) {
1156 Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);
1157 if (EFI_ERROR (Status)) {
1158 BlockIo = NULL;
1159 }
1160 if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||
1161 (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
1162 (MediaType == 2 && BlockIo == NULL)
1163 ) {
1164 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
1165 FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);
1166 if (FileBuffer != NULL) {
1167 *FullPath = FullDevicePath;
1168 FreePool (Handles);
1169 return FileBuffer;
1170 }
1171 FreePool (FullDevicePath);
1172 }
1173 }
1174 }
1175
1176 if (Handles != NULL) {
1177 FreePool (Handles);
1178 }
1179
1180 *FullPath = NULL;
1181 return NULL;
1182 }
1183
1184 /**
1185 Expand URI device path node to be full device path in platform.
1186
1187 @param FilePath The device path pointing to a load option.
1188 It could be a short-form device path.
1189 @param FullPath Return the full device path of the load option after
1190 short-form device path expanding.
1191 Caller is responsible to free it.
1192 @param FileSize Return the load option size.
1193
1194 @return The load option buffer. Caller is responsible to free the memory.
1195 **/
1196 VOID *
1197 BmExpandUriDevicePath (
1198 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1199 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1200 OUT UINTN *FileSize
1201 )
1202 {
1203 EFI_STATUS Status;
1204 UINTN Index;
1205 UINTN HandleCount;
1206 EFI_HANDLE *Handles;
1207 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1208 VOID *FileBuffer;
1209
1210 EfiBootManagerConnectAll ();
1211 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
1212 if (EFI_ERROR (Status)) {
1213 HandleCount = 0;
1214 Handles = NULL;
1215 }
1216
1217 FileBuffer = NULL;
1218
1219 for (Index = 0; Index < HandleCount; Index++) {
1220 Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadFileProtocolGuid, (VOID *) &LoadFile);
1221 ASSERT_EFI_ERROR (Status);
1222
1223 FileBuffer = NULL;
1224 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);
1225 if (Status == EFI_BUFFER_TOO_SMALL) {
1226 FileBuffer = AllocatePool (*FileSize);
1227 if (FileBuffer == NULL) {
1228 break;
1229 }
1230 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);
1231 }
1232
1233 if (!EFI_ERROR (Status)) {
1234 //
1235 // LoadFile() returns a file buffer mapping to a file system.
1236 //
1237 if (Status == EFI_WARN_FILE_SYSTEM) {
1238 return BmGetFileBufferFromLoadFileFileSystem (Handles[Index], FullPath, FileSize);
1239 }
1240
1241 ASSERT (Status == EFI_SUCCESS);
1242 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
1243 break;
1244 }
1245
1246 if (FileBuffer != NULL) {
1247 FreePool (FileBuffer);
1248 }
1249 }
1250
1251 if (Handles != NULL) {
1252 FreePool (Handles);
1253 }
1254
1255 return FileBuffer;
1256 }
1257
1258 /**
1259 Save the partition DevicePath to the CachedDevicePath as the first instance.
1260
1261 @param CachedDevicePath The device path cache.
1262 @param DevicePath The partition device path to be cached.
1263 **/
1264 VOID
1265 BmCachePartitionDevicePath (
1266 IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
1267 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1268 )
1269 {
1270 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1271 UINTN Count;
1272
1273 if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
1274 TempDevicePath = *CachedDevicePath;
1275 *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
1276 FreePool (TempDevicePath);
1277 }
1278
1279 if (*CachedDevicePath == NULL) {
1280 *CachedDevicePath = DuplicateDevicePath (DevicePath);
1281 return;
1282 }
1283
1284 TempDevicePath = *CachedDevicePath;
1285 *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
1286 if (TempDevicePath != NULL) {
1287 FreePool (TempDevicePath);
1288 }
1289
1290 //
1291 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
1292 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
1293 //
1294 Count = 0;
1295 TempDevicePath = *CachedDevicePath;
1296 while (!IsDevicePathEnd (TempDevicePath)) {
1297 TempDevicePath = NextDevicePathNode (TempDevicePath);
1298 //
1299 // Parse one instance
1300 //
1301 while (!IsDevicePathEndType (TempDevicePath)) {
1302 TempDevicePath = NextDevicePathNode (TempDevicePath);
1303 }
1304 Count++;
1305 //
1306 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
1307 //
1308 if (Count == 12) {
1309 SetDevicePathEndNode (TempDevicePath);
1310 break;
1311 }
1312 }
1313 }
1314
1315 /**
1316 Expand a device path that starts with a hard drive media device path node to be a
1317 full device path that includes the full hardware path to the device. We need
1318 to do this so it can be booted. As an optimization the front match (the part point
1319 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
1320 so a connect all is not required on every boot. All successful history device path
1321 which point to partition node (the front part) will be saved.
1322
1323 @param FilePath The device path pointing to a load option.
1324 It could be a short-form device path.
1325 @param FullPath Return the full device path of the load option after
1326 short-form device path expanding.
1327 Caller is responsible to free it.
1328 @param FileSize Return the load option size.
1329
1330 @return The load option buffer. Caller is responsible to free the memory.
1331 **/
1332 VOID *
1333 BmExpandPartitionDevicePath (
1334 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1335 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1336 OUT UINTN *FileSize
1337 )
1338 {
1339 EFI_STATUS Status;
1340 UINTN BlockIoHandleCount;
1341 EFI_HANDLE *BlockIoBuffer;
1342 VOID *FileBuffer;
1343 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
1344 UINTN Index;
1345 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
1346 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
1347 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1348 UINTN CachedDevicePathSize;
1349 BOOLEAN NeedAdjust;
1350 EFI_DEVICE_PATH_PROTOCOL *Instance;
1351 UINTN Size;
1352
1353 FileBuffer = NULL;
1354 //
1355 // Check if there is prestore 'HDDP' variable.
1356 // If exist, search the front path which point to partition node in the variable instants.
1357 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
1358 //
1359 GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
1360
1361 //
1362 // Delete the invalid 'HDDP' variable.
1363 //
1364 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
1365 FreePool (CachedDevicePath);
1366 CachedDevicePath = NULL;
1367 Status = gRT->SetVariable (
1368 L"HDDP",
1369 &mBmHardDriveBootVariableGuid,
1370 0,
1371 0,
1372 NULL
1373 );
1374 ASSERT_EFI_ERROR (Status);
1375 }
1376
1377 if (CachedDevicePath != NULL) {
1378 TempNewDevicePath = CachedDevicePath;
1379 NeedAdjust = FALSE;
1380 do {
1381 //
1382 // Check every instance of the variable
1383 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
1384 // partial partition boot option. Second, check whether the instance could be connected.
1385 //
1386 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
1387 if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
1388 //
1389 // Connect the device path instance, the device path point to hard drive media device path node
1390 // e.g. ACPI() /PCI()/ATA()/Partition()
1391 //
1392 Status = EfiBootManagerConnectDevicePath (Instance, NULL);
1393 if (!EFI_ERROR (Status)) {
1394 TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
1395 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
1396 FreePool (TempDevicePath);
1397
1398 if (FileBuffer != NULL) {
1399 //
1400 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
1401 //
1402 if (NeedAdjust) {
1403 BmCachePartitionDevicePath (&CachedDevicePath, Instance);
1404 //
1405 // Save the matching Device Path so we don't need to do a connect all next time
1406 // Failing to save only impacts performance next time expanding the short-form device path
1407 //
1408 Status = gRT->SetVariable (
1409 L"HDDP",
1410 &mBmHardDriveBootVariableGuid,
1411 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1412 GetDevicePathSize (CachedDevicePath),
1413 CachedDevicePath
1414 );
1415 }
1416
1417 FreePool (Instance);
1418 FreePool (CachedDevicePath);
1419 return FileBuffer;
1420 }
1421 }
1422 }
1423 //
1424 // Come here means the first instance is not matched
1425 //
1426 NeedAdjust = TRUE;
1427 FreePool(Instance);
1428 } while (TempNewDevicePath != NULL);
1429 }
1430
1431 //
1432 // If we get here we fail to find or 'HDDP' not exist, and now we need
1433 // to search all devices in the system for a matched partition
1434 //
1435 EfiBootManagerConnectAll ();
1436 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
1437 if (EFI_ERROR (Status)) {
1438 BlockIoHandleCount = 0;
1439 BlockIoBuffer = NULL;
1440 }
1441 //
1442 // Loop through all the device handles that support the BLOCK_IO Protocol
1443 //
1444 for (Index = 0; Index < BlockIoHandleCount; Index++) {
1445 BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
1446 if (BlockIoDevicePath == NULL) {
1447 continue;
1448 }
1449
1450 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
1451 //
1452 // Find the matched partition device path
1453 //
1454 TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
1455 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
1456 FreePool (TempDevicePath);
1457
1458 if (FileBuffer != NULL) {
1459 BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
1460
1461 //
1462 // Save the matching Device Path so we don't need to do a connect all next time
1463 // Failing to save only impacts performance next time expanding the short-form device path
1464 //
1465 Status = gRT->SetVariable (
1466 L"HDDP",
1467 &mBmHardDriveBootVariableGuid,
1468 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1469 GetDevicePathSize (CachedDevicePath),
1470 CachedDevicePath
1471 );
1472
1473 break;
1474 }
1475 }
1476 }
1477
1478 if (CachedDevicePath != NULL) {
1479 FreePool (CachedDevicePath);
1480 }
1481 if (BlockIoBuffer != NULL) {
1482 FreePool (BlockIoBuffer);
1483 }
1484 return FileBuffer;
1485 }
1486
1487 /**
1488 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
1489 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
1490
1491 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
1492 @param FullPath Return the full device path pointing to the load option.
1493 @param FileSize Return the size of the load option.
1494
1495 @return The load option buffer.
1496 **/
1497 VOID *
1498 BmExpandMediaDevicePath (
1499 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1500 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1501 OUT UINTN *FileSize
1502 )
1503 {
1504 EFI_STATUS Status;
1505 EFI_HANDLE Handle;
1506 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1507 VOID *Buffer;
1508 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1509 UINTN Size;
1510 UINTN TempSize;
1511 EFI_HANDLE *SimpleFileSystemHandles;
1512 UINTN NumberSimpleFileSystemHandles;
1513 UINTN Index;
1514 VOID *FileBuffer;
1515 UINT32 AuthenticationStatus;
1516
1517 //
1518 // Check whether the device is connected
1519 //
1520 TempDevicePath = DevicePath;
1521 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1522 if (!EFI_ERROR (Status)) {
1523 ASSERT (IsDevicePathEnd (TempDevicePath));
1524
1525 TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
1526 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
1527 if (FileBuffer == NULL) {
1528 FreePool (TempDevicePath);
1529 TempDevicePath = NULL;
1530 }
1531 *FullPath = TempDevicePath;
1532 return FileBuffer;
1533 }
1534
1535 //
1536 // For device boot option only pointing to the removable device handle,
1537 // should make sure all its children handles (its child partion or media handles) are created and connected.
1538 //
1539 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1540
1541 //
1542 // Issue a dummy read to the device to check for media change.
1543 // When the removable media is changed, any Block IO read/write will
1544 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1545 // returned. After the Block IO protocol is reinstalled, subsequent
1546 // Block IO read/write will success.
1547 //
1548 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1549 ASSERT_EFI_ERROR (Status);
1550 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1551 ASSERT_EFI_ERROR (Status);
1552 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1553 if (Buffer != NULL) {
1554 BlockIo->ReadBlocks (
1555 BlockIo,
1556 BlockIo->Media->MediaId,
1557 0,
1558 BlockIo->Media->BlockSize,
1559 Buffer
1560 );
1561 FreePool (Buffer);
1562 }
1563
1564 //
1565 // Detect the the default boot file from removable Media
1566 //
1567 FileBuffer = NULL;
1568 *FullPath = NULL;
1569 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
1570 gBS->LocateHandleBuffer (
1571 ByProtocol,
1572 &gEfiSimpleFileSystemProtocolGuid,
1573 NULL,
1574 &NumberSimpleFileSystemHandles,
1575 &SimpleFileSystemHandles
1576 );
1577 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1578 //
1579 // Get the device path size of SimpleFileSystem handle
1580 //
1581 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1582 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
1583 //
1584 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1585 //
1586 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
1587 TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
1588 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
1589 if (FileBuffer != NULL) {
1590 *FullPath = TempDevicePath;
1591 break;
1592 }
1593 FreePool (TempDevicePath);
1594 }
1595 }
1596
1597 if (SimpleFileSystemHandles != NULL) {
1598 FreePool (SimpleFileSystemHandles);
1599 }
1600
1601 return FileBuffer;
1602 }
1603
1604 /**
1605 Check whether Left and Right are the same without matching the specific
1606 device path data in IP device path and URI device path node.
1607
1608 @retval TRUE Left and Right are the same.
1609 @retval FALSE Left and Right are the different.
1610 **/
1611 BOOLEAN
1612 BmMatchHttpBootDevicePath (
1613 IN EFI_DEVICE_PATH_PROTOCOL *Left,
1614 IN EFI_DEVICE_PATH_PROTOCOL *Right
1615 )
1616 {
1617 for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
1618 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
1619 ) {
1620 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
1621 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
1622 return FALSE;
1623 }
1624
1625 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
1626 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
1627 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
1628 ) {
1629 return FALSE;
1630 }
1631 }
1632 }
1633 return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
1634 }
1635
1636 /**
1637 Get the file buffer from the file system produced by Load File instance.
1638
1639 @param LoadFileHandle The handle of LoadFile instance.
1640 @param FullPath Return the full device path pointing to the load option.
1641 @param FileSize Return the size of the load option.
1642
1643 @return The load option buffer.
1644 **/
1645 VOID *
1646 BmGetFileBufferFromLoadFileFileSystem (
1647 IN EFI_HANDLE LoadFileHandle,
1648 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1649 OUT UINTN *FileSize
1650 )
1651 {
1652 EFI_STATUS Status;
1653 EFI_HANDLE Handle;
1654 EFI_HANDLE *Handles;
1655 UINTN HandleCount;
1656 UINTN Index;
1657 EFI_DEVICE_PATH_PROTOCOL *Node;
1658
1659 Status = gBS->LocateHandleBuffer (
1660 ByProtocol,
1661 &gEfiBlockIoProtocolGuid,
1662 NULL,
1663 &HandleCount,
1664 &Handles
1665 );
1666 if (EFI_ERROR (Status)) {
1667 Handles = NULL;
1668 HandleCount = 0;
1669 }
1670 for (Index = 0; Index < HandleCount; Index++) {
1671 Node = DevicePathFromHandle (Handles[Index]);
1672 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1673 if (!EFI_ERROR (Status) &&
1674 (Handle == LoadFileHandle) &&
1675 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
1676 Handle = Handles[Index];
1677 break;
1678 }
1679 }
1680
1681 if (Handles != NULL) {
1682 FreePool (Handles);
1683 }
1684
1685 if (Index != HandleCount) {
1686 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
1687 } else {
1688 return NULL;
1689 }
1690 }
1691
1692 /**
1693 Get the file buffer from Load File instance.
1694
1695 @param FilePath The media device path pointing to a LoadFile instance.
1696 @param FullPath Return the full device path pointing to the load option.
1697 @param FileSize Return the size of the load option.
1698
1699 @return The load option buffer.
1700 **/
1701 VOID *
1702 BmGetFileBufferFromLoadFile (
1703 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1704 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1705 OUT UINTN *FileSize
1706 )
1707 {
1708 EFI_STATUS Status;
1709 EFI_HANDLE Handle;
1710 VOID *FileBuffer;
1711 EFI_HANDLE *Handles;
1712 UINTN HandleCount;
1713 UINTN Index;
1714 EFI_DEVICE_PATH_PROTOCOL *Node;
1715 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1716 UINTN BufferSize;
1717
1718 //
1719 // Get file buffer from load file instance.
1720 //
1721 Node = FilePath;
1722 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1723 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1724 //
1725 // When wide match happens, pass full device path to LoadFile (),
1726 // otherwise, pass remaining device path to LoadFile ().
1727 //
1728 FilePath = Node;
1729 } else {
1730 Handle = NULL;
1731 //
1732 // Use wide match algorithm to find one when
1733 // cannot find a LoadFile instance to exactly match the FilePath
1734 //
1735 Status = gBS->LocateHandleBuffer (
1736 ByProtocol,
1737 &gEfiLoadFileProtocolGuid,
1738 NULL,
1739 &HandleCount,
1740 &Handles
1741 );
1742 if (EFI_ERROR (Status)) {
1743 Handles = NULL;
1744 HandleCount = 0;
1745 }
1746 for (Index = 0; Index < HandleCount; Index++) {
1747 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
1748 Handle = Handles[Index];
1749 break;
1750 }
1751 }
1752 if (Handles != NULL) {
1753 FreePool (Handles);
1754 }
1755 }
1756
1757 if (Handle == NULL) {
1758 return NULL;
1759 }
1760
1761 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);
1762 ASSERT_EFI_ERROR (Status);
1763
1764 BufferSize = 0;
1765 FileBuffer = NULL;
1766 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1767 if (Status == EFI_BUFFER_TOO_SMALL) {
1768 FileBuffer = AllocatePool (BufferSize);
1769 if (FileBuffer != NULL) {
1770 Status = EFI_SUCCESS;
1771 }
1772 }
1773
1774 if (!EFI_ERROR (Status)) {
1775 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1776 }
1777
1778 if (!EFI_ERROR (Status)) {
1779 //
1780 // LoadFile() returns a file buffer mapping to a file system.
1781 //
1782 if (Status == EFI_WARN_FILE_SYSTEM) {
1783 return BmGetFileBufferFromLoadFileFileSystem (Handle, FullPath, FileSize);
1784 }
1785
1786 ASSERT (Status == EFI_SUCCESS);
1787 //
1788 // LoadFile () may cause the device path of the Handle be updated.
1789 //
1790 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));
1791 *FileSize = BufferSize;
1792 return FileBuffer;
1793 } else {
1794 return NULL;
1795 }
1796 }
1797
1798 /**
1799 Get the load option by its device path.
1800
1801 @param FilePath The device path pointing to a load option.
1802 It could be a short-form device path.
1803 @param FullPath Return the full device path of the load option after
1804 short-form device path expanding.
1805 Caller is responsible to free it.
1806 @param FileSize Return the load option size.
1807
1808 @return The load option buffer. Caller is responsible to free the memory.
1809 **/
1810 VOID *
1811 BmGetLoadOptionBuffer (
1812 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1813 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1814 OUT UINTN *FileSize
1815 )
1816 {
1817 EFI_HANDLE Handle;
1818 VOID *FileBuffer;
1819 UINT32 AuthenticationStatus;
1820 EFI_DEVICE_PATH_PROTOCOL *Node;
1821 EFI_STATUS Status;
1822
1823 ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
1824
1825 EfiBootManagerConnectDevicePath (FilePath, NULL);
1826
1827 *FullPath = NULL;
1828 *FileSize = 0;
1829 FileBuffer = NULL;
1830
1831 //
1832 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1833 //
1834 Node = FilePath;
1835 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1836 if (EFI_ERROR (Status)) {
1837 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
1838 }
1839
1840 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1841 return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
1842 }
1843
1844 //
1845 // Expand the short-form device path to full device path
1846 //
1847 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1848 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
1849 //
1850 // Expand the Harddrive device path
1851 //
1852 return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
1853 } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1854 (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
1855 //
1856 // Expand the File-path device path
1857 //
1858 return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
1859 } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
1860 (DevicePathSubType (FilePath) == MSG_URI_DP)) {
1861 //
1862 // Expand the URI device path
1863 //
1864 return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
1865 } else {
1866 for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
1867 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
1868 ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
1869 break;
1870 }
1871 }
1872
1873 if (!IsDevicePathEnd (Node)) {
1874 //
1875 // Expand the USB WWID/Class device path
1876 //
1877 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1878 if ((FileBuffer == NULL) && (FilePath == Node)) {
1879 //
1880 // Boot Option device path starts with USB Class or USB WWID device path.
1881 // For Boot Option device path which doesn't begin with the USB Class or
1882 // USB WWID device path, it's not needed to connect again here.
1883 //
1884 BmConnectUsbShortFormDevicePath (FilePath);
1885 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1886 }
1887 return FileBuffer;
1888 }
1889 }
1890
1891 //
1892 // Get file buffer from FV file path.
1893 //
1894 if (BmIsFvFilePath (FilePath)) {
1895 return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
1896 }
1897
1898 //
1899 // Get file buffer from simple file system.
1900 //
1901 Node = FilePath;
1902 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1903 if (!EFI_ERROR (Status)) {
1904 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
1905 if (FileBuffer != NULL) {
1906 *FullPath = DuplicateDevicePath (FilePath);
1907 }
1908 return FileBuffer;
1909 }
1910
1911 return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);
1912 }
1913
1914 /**
1915 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1916 also signals the EFI ready to boot event. If the device path for the option
1917 starts with a BBS device path a legacy boot is attempted via the registered
1918 gLegacyBoot function. Short form device paths are also supported via this
1919 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1920 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1921 If the BootOption Device Path fails the removable media boot algorithm
1922 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1923 is tried per processor type)
1924
1925 @param BootOption Boot Option to try and boot.
1926 On return, BootOption->Status contains the boot status.
1927 EFI_SUCCESS BootOption was booted
1928 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1929 registered via EfiBootManagerInitialize().
1930 EFI_NOT_FOUND The BootOption was not found on the system
1931 !EFI_SUCCESS BootOption failed with this error status
1932
1933 **/
1934 VOID
1935 EFIAPI
1936 EfiBootManagerBoot (
1937 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1938 )
1939 {
1940 EFI_STATUS Status;
1941 EFI_HANDLE ImageHandle;
1942 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1943 UINT16 Uint16;
1944 UINTN OptionNumber;
1945 UINTN OriginalOptionNumber;
1946 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1947 EFI_DEVICE_PATH_PROTOCOL *Node;
1948 EFI_HANDLE FvHandle;
1949 VOID *FileBuffer;
1950 UINTN FileSize;
1951 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
1952 EFI_EVENT LegacyBootEvent;
1953
1954 if (BootOption == NULL) {
1955 return;
1956 }
1957
1958 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
1959 BootOption->Status = EFI_INVALID_PARAMETER;
1960 return;
1961 }
1962
1963 //
1964 // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
1965 //
1966 OptionNumber = BmFindBootOptionInVariable (BootOption);
1967 if (OptionNumber == LoadOptionNumberUnassigned) {
1968 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
1969 if (!EFI_ERROR (Status)) {
1970 //
1971 // Save the BootOption->OptionNumber to restore later
1972 //
1973 OptionNumber = Uint16;
1974 OriginalOptionNumber = BootOption->OptionNumber;
1975 BootOption->OptionNumber = OptionNumber;
1976 Status = EfiBootManagerLoadOptionToVariable (BootOption);
1977 BootOption->OptionNumber = OriginalOptionNumber;
1978 }
1979
1980 if (EFI_ERROR (Status)) {
1981 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
1982 BootOption->Status = Status;
1983 return ;
1984 }
1985 }
1986
1987 //
1988 // 2. Set BootCurrent
1989 //
1990 Uint16 = (UINT16) OptionNumber;
1991 BmSetVariableAndReportStatusCodeOnError (
1992 L"BootCurrent",
1993 &gEfiGlobalVariableGuid,
1994 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1995 sizeof (UINT16),
1996 &Uint16
1997 );
1998
1999 //
2000 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
2001 // the boot option.
2002 //
2003 Node = BootOption->FilePath;
2004 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
2005 if (!EFI_ERROR (Status) && CompareGuid (
2006 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
2007 PcdGetPtr (PcdBootManagerMenuFile)
2008 )) {
2009 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
2010 BmStopHotkeyService (NULL, NULL);
2011 } else {
2012 EfiSignalEventReadyToBoot();
2013 //
2014 // Report Status Code to indicate ReadyToBoot was signalled
2015 //
2016 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
2017 //
2018 // 4. Repair system through DriverHealth protocol
2019 //
2020 BmRepairAllControllers ();
2021 }
2022
2023 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
2024
2025 //
2026 // 5. Load EFI boot option to ImageHandle
2027 //
2028 ImageHandle = NULL;
2029 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
2030 Status = EFI_NOT_FOUND;
2031 FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
2032 DEBUG_CODE (
2033 if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
2034 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
2035 BmPrintDp (BootOption->FilePath);
2036 DEBUG ((EFI_D_INFO, " -> "));
2037 BmPrintDp (FilePath);
2038 DEBUG ((EFI_D_INFO, "\n"));
2039 }
2040 );
2041 if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
2042 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
2043 Status = gBS->LoadImage (
2044 TRUE,
2045 gImageHandle,
2046 FilePath,
2047 FileBuffer,
2048 FileSize,
2049 &ImageHandle
2050 );
2051 }
2052 if (FileBuffer != NULL) {
2053 FreePool (FileBuffer);
2054 }
2055 if (FilePath != NULL) {
2056 FreePool (FilePath);
2057 }
2058
2059 if (EFI_ERROR (Status)) {
2060 //
2061 // Report Status Code to indicate that the failure to load boot option
2062 //
2063 REPORT_STATUS_CODE (
2064 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2065 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
2066 );
2067 BootOption->Status = Status;
2068 return;
2069 }
2070 }
2071
2072 //
2073 // 6. Adjust the different type memory page number just before booting
2074 // and save the updated info into the variable for next boot to use
2075 //
2076 BmSetMemoryTypeInformationVariable (
2077 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
2078 );
2079
2080 DEBUG_CODE_BEGIN();
2081 if (BootOption->Description == NULL) {
2082 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
2083 } else {
2084 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
2085 }
2086 DEBUG_CODE_END();
2087
2088 //
2089 // Check to see if we should legacy BOOT. If yes then do the legacy boot
2090 // Write boot to OS performance data for Legacy boot
2091 //
2092 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
2093 if (mBmLegacyBoot != NULL) {
2094 //
2095 // Write boot to OS performance data for legacy boot.
2096 //
2097 PERF_CODE (
2098 //
2099 // Create an event to be signalled when Legacy Boot occurs to write performance data.
2100 //
2101 Status = EfiCreateEventLegacyBootEx(
2102 TPL_NOTIFY,
2103 BmWriteBootToOsPerformanceData,
2104 NULL,
2105 &LegacyBootEvent
2106 );
2107 ASSERT_EFI_ERROR (Status);
2108 );
2109
2110 mBmLegacyBoot (BootOption);
2111 } else {
2112 BootOption->Status = EFI_UNSUPPORTED;
2113 }
2114
2115 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
2116 return;
2117 }
2118
2119 //
2120 // Provide the image with its load options
2121 //
2122 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
2123 ASSERT_EFI_ERROR (Status);
2124
2125 if (!BmIsAutoCreateBootOption (BootOption)) {
2126 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
2127 ImageInfo->LoadOptions = BootOption->OptionalData;
2128 }
2129
2130 //
2131 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2132 //
2133 ImageInfo->ParentHandle = NULL;
2134
2135 //
2136 // Before calling the image, enable the Watchdog Timer for 5 minutes period
2137 //
2138 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
2139
2140 //
2141 // Write boot to OS performance data for UEFI boot
2142 //
2143 PERF_CODE (
2144 BmWriteBootToOsPerformanceData (NULL, NULL);
2145 );
2146
2147 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
2148
2149 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
2150 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
2151 BootOption->Status = Status;
2152 if (EFI_ERROR (Status)) {
2153 //
2154 // Report Status Code to indicate that boot failure
2155 //
2156 REPORT_STATUS_CODE (
2157 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2158 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
2159 );
2160 }
2161 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
2162
2163 //
2164 // Clear the Watchdog Timer after the image returns
2165 //
2166 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
2167
2168 //
2169 // Set Logo status invalid after trying one boot option
2170 //
2171 BootLogo = NULL;
2172 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
2173 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
2174 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
2175 ASSERT_EFI_ERROR (Status);
2176 }
2177
2178 //
2179 // Clear Boot Current
2180 //
2181 Status = gRT->SetVariable (
2182 L"BootCurrent",
2183 &gEfiGlobalVariableGuid,
2184 0,
2185 0,
2186 NULL
2187 );
2188 //
2189 // Deleting variable with current variable implementation shouldn't fail.
2190 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
2191 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
2192 //
2193 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
2194 }
2195
2196 /**
2197 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2198 instances, has the same partition node with HardDriveDevicePath device path
2199
2200 @param BlockIoDevicePath Multi device path instances which need to check
2201 @param HardDriveDevicePath A device path which starts with a hard drive media
2202 device path.
2203
2204 @retval TRUE There is a matched device path instance.
2205 @retval FALSE There is no matched device path instance.
2206
2207 **/
2208 BOOLEAN
2209 BmMatchPartitionDevicePathNode (
2210 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
2211 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
2212 )
2213 {
2214 HARDDRIVE_DEVICE_PATH *Node;
2215
2216 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
2217 return FALSE;
2218 }
2219
2220 //
2221 // find the partition device path node
2222 //
2223 while (!IsDevicePathEnd (BlockIoDevicePath)) {
2224 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
2225 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
2226 ) {
2227 break;
2228 }
2229
2230 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
2231 }
2232
2233 if (IsDevicePathEnd (BlockIoDevicePath)) {
2234 return FALSE;
2235 }
2236
2237 //
2238 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2239 //
2240 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
2241
2242 //
2243 // Match Signature and PartitionNumber.
2244 // Unused bytes in Signature are initiaized with zeros.
2245 //
2246 return (BOOLEAN) (
2247 (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
2248 (Node->MBRType == HardDriveDevicePath->MBRType) &&
2249 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
2250 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
2251 );
2252 }
2253
2254 /**
2255 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
2256 unique description.
2257
2258 @param BootOptions Array of boot options.
2259 @param BootOptionCount Count of boot options.
2260 **/
2261 VOID
2262 BmMakeBootOptionDescriptionUnique (
2263 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
2264 UINTN BootOptionCount
2265 )
2266 {
2267 UINTN Base;
2268 UINTN Index;
2269 UINTN DescriptionSize;
2270 UINTN MaxSuffixSize;
2271 BOOLEAN *Visited;
2272 UINTN MatchCount;
2273
2274 if (BootOptionCount == 0) {
2275 return;
2276 }
2277
2278 //
2279 // Calculate the maximum buffer size for the number suffix.
2280 // The initial sizeof (CHAR16) is for the blank space before the number.
2281 //
2282 MaxSuffixSize = sizeof (CHAR16);
2283 for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
2284 MaxSuffixSize += sizeof (CHAR16);
2285 }
2286
2287 Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
2288 ASSERT (Visited != NULL);
2289
2290 for (Base = 0; Base < BootOptionCount; Base++) {
2291 if (!Visited[Base]) {
2292 MatchCount = 1;
2293 Visited[Base] = TRUE;
2294 DescriptionSize = StrSize (BootOptions[Base].Description);
2295 for (Index = Base + 1; Index < BootOptionCount; Index++) {
2296 if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {
2297 Visited[Index] = TRUE;
2298 MatchCount++;
2299 FreePool (BootOptions[Index].Description);
2300 BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
2301 UnicodeSPrint (
2302 BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,
2303 L"%s %d",
2304 BootOptions[Base].Description, MatchCount
2305 );
2306 }
2307 }
2308 }
2309 }
2310
2311 FreePool (Visited);
2312 }
2313
2314 /**
2315 Emuerate all possible bootable medias in the following order:
2316 1. Removable BlockIo - The boot option only points to the removable media
2317 device, like USB key, DVD, Floppy etc.
2318 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
2319 like HardDisk.
2320 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
2321 SimpleFileSystem Protocol, but not supporting BlockIo
2322 protocol.
2323 4. LoadFile - The boot option points to the media supporting
2324 LoadFile protocol.
2325 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
2326
2327 @param BootOptionCount Return the boot option count which has been found.
2328
2329 @retval Pointer to the boot option array.
2330 **/
2331 EFI_BOOT_MANAGER_LOAD_OPTION *
2332 BmEnumerateBootOptions (
2333 UINTN *BootOptionCount
2334 )
2335 {
2336 EFI_STATUS Status;
2337 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2338 UINTN HandleCount;
2339 EFI_HANDLE *Handles;
2340 EFI_BLOCK_IO_PROTOCOL *BlkIo;
2341 UINTN Removable;
2342 UINTN Index;
2343 CHAR16 *Description;
2344
2345 ASSERT (BootOptionCount != NULL);
2346
2347 *BootOptionCount = 0;
2348 BootOptions = NULL;
2349
2350 //
2351 // Parse removable block io followed by fixed block io
2352 //
2353 gBS->LocateHandleBuffer (
2354 ByProtocol,
2355 &gEfiBlockIoProtocolGuid,
2356 NULL,
2357 &HandleCount,
2358 &Handles
2359 );
2360
2361 for (Removable = 0; Removable < 2; Removable++) {
2362 for (Index = 0; Index < HandleCount; Index++) {
2363 Status = gBS->HandleProtocol (
2364 Handles[Index],
2365 &gEfiBlockIoProtocolGuid,
2366 (VOID **) &BlkIo
2367 );
2368 if (EFI_ERROR (Status)) {
2369 continue;
2370 }
2371
2372 //
2373 // Skip the logical partitions
2374 //
2375 if (BlkIo->Media->LogicalPartition) {
2376 continue;
2377 }
2378
2379 //
2380 // Skip the fixed block io then the removable block io
2381 //
2382 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
2383 continue;
2384 }
2385
2386 Description = BmGetBootDescription (Handles[Index]);
2387 BootOptions = ReallocatePool (
2388 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2389 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2390 BootOptions
2391 );
2392 ASSERT (BootOptions != NULL);
2393
2394 Status = EfiBootManagerInitializeLoadOption (
2395 &BootOptions[(*BootOptionCount)++],
2396 LoadOptionNumberUnassigned,
2397 LoadOptionTypeBoot,
2398 LOAD_OPTION_ACTIVE,
2399 Description,
2400 DevicePathFromHandle (Handles[Index]),
2401 NULL,
2402 0
2403 );
2404 ASSERT_EFI_ERROR (Status);
2405
2406 FreePool (Description);
2407 }
2408 }
2409
2410 if (HandleCount != 0) {
2411 FreePool (Handles);
2412 }
2413
2414 //
2415 // Parse simple file system not based on block io
2416 //
2417 gBS->LocateHandleBuffer (
2418 ByProtocol,
2419 &gEfiSimpleFileSystemProtocolGuid,
2420 NULL,
2421 &HandleCount,
2422 &Handles
2423 );
2424 for (Index = 0; Index < HandleCount; Index++) {
2425 Status = gBS->HandleProtocol (
2426 Handles[Index],
2427 &gEfiBlockIoProtocolGuid,
2428 (VOID **) &BlkIo
2429 );
2430 if (!EFI_ERROR (Status)) {
2431 //
2432 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
2433 //
2434 continue;
2435 }
2436 Description = BmGetBootDescription (Handles[Index]);
2437 BootOptions = ReallocatePool (
2438 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2439 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2440 BootOptions
2441 );
2442 ASSERT (BootOptions != NULL);
2443
2444 Status = EfiBootManagerInitializeLoadOption (
2445 &BootOptions[(*BootOptionCount)++],
2446 LoadOptionNumberUnassigned,
2447 LoadOptionTypeBoot,
2448 LOAD_OPTION_ACTIVE,
2449 Description,
2450 DevicePathFromHandle (Handles[Index]),
2451 NULL,
2452 0
2453 );
2454 ASSERT_EFI_ERROR (Status);
2455 FreePool (Description);
2456 }
2457
2458 if (HandleCount != 0) {
2459 FreePool (Handles);
2460 }
2461
2462 //
2463 // Parse load file, assuming UEFI Network boot option
2464 //
2465 gBS->LocateHandleBuffer (
2466 ByProtocol,
2467 &gEfiLoadFileProtocolGuid,
2468 NULL,
2469 &HandleCount,
2470 &Handles
2471 );
2472 for (Index = 0; Index < HandleCount; Index++) {
2473
2474 Description = BmGetBootDescription (Handles[Index]);
2475 BootOptions = ReallocatePool (
2476 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
2477 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
2478 BootOptions
2479 );
2480 ASSERT (BootOptions != NULL);
2481
2482 Status = EfiBootManagerInitializeLoadOption (
2483 &BootOptions[(*BootOptionCount)++],
2484 LoadOptionNumberUnassigned,
2485 LoadOptionTypeBoot,
2486 LOAD_OPTION_ACTIVE,
2487 Description,
2488 DevicePathFromHandle (Handles[Index]),
2489 NULL,
2490 0
2491 );
2492 ASSERT_EFI_ERROR (Status);
2493 FreePool (Description);
2494 }
2495
2496 if (HandleCount != 0) {
2497 FreePool (Handles);
2498 }
2499
2500 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
2501 return BootOptions;
2502 }
2503
2504 /**
2505 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
2506 **/
2507 VOID
2508 EFIAPI
2509 EfiBootManagerRefreshAllBootOption (
2510 VOID
2511 )
2512 {
2513 EFI_STATUS Status;
2514 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
2515 UINTN NvBootOptionCount;
2516 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2517 UINTN BootOptionCount;
2518 UINTN Index;
2519
2520 //
2521 // Optionally refresh the legacy boot option
2522 //
2523 if (mBmRefreshLegacyBootOption != NULL) {
2524 mBmRefreshLegacyBootOption ();
2525 }
2526
2527 BootOptions = BmEnumerateBootOptions (&BootOptionCount);
2528 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
2529
2530 //
2531 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
2532 //
2533 for (Index = 0; Index < BootOptionCount; Index++) {
2534 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
2535 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
2536 }
2537
2538 //
2539 // Remove invalid EFI boot options from NV
2540 //
2541 for (Index = 0; Index < NvBootOptionCount; Index++) {
2542 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
2543 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
2544 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
2545 ) {
2546 //
2547 // Only check those added by BDS
2548 // so that the boot options added by end-user or OS installer won't be deleted
2549 //
2550 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
2551 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
2552 //
2553 // Deleting variable with current variable implementation shouldn't fail.
2554 //
2555 ASSERT_EFI_ERROR (Status);
2556 }
2557 }
2558 }
2559
2560 //
2561 // Add new EFI boot options to NV
2562 //
2563 for (Index = 0; Index < BootOptionCount; Index++) {
2564 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
2565 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
2566 //
2567 // Try best to add the boot options so continue upon failure.
2568 //
2569 }
2570 }
2571
2572 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2573 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
2574 }
2575
2576 /**
2577 This function is called to create the boot option for the Boot Manager Menu.
2578
2579 The Boot Manager Menu is shown after successfully booting a boot option.
2580 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2581
2582 @param BootOption Return the boot option of the Boot Manager Menu
2583
2584 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2585 @retval Status Return status of gRT->SetVariable (). BootOption still points
2586 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2587 **/
2588 EFI_STATUS
2589 BmRegisterBootManagerMenu (
2590 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2591 )
2592 {
2593 EFI_STATUS Status;
2594 CHAR16 *Description;
2595 UINTN DescriptionLength;
2596 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2597 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2598 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
2599
2600 Status = GetSectionFromFv (
2601 PcdGetPtr (PcdBootManagerMenuFile),
2602 EFI_SECTION_USER_INTERFACE,
2603 0,
2604 (VOID **) &Description,
2605 &DescriptionLength
2606 );
2607 if (EFI_ERROR (Status)) {
2608 Description = NULL;
2609 }
2610
2611 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
2612 Status = gBS->HandleProtocol (
2613 gImageHandle,
2614 &gEfiLoadedImageProtocolGuid,
2615 (VOID **) &LoadedImage
2616 );
2617 ASSERT_EFI_ERROR (Status);
2618 DevicePath = AppendDevicePathNode (
2619 DevicePathFromHandle (LoadedImage->DeviceHandle),
2620 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
2621 );
2622 ASSERT (DevicePath != NULL);
2623
2624 Status = EfiBootManagerInitializeLoadOption (
2625 BootOption,
2626 LoadOptionNumberUnassigned,
2627 LoadOptionTypeBoot,
2628 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
2629 (Description != NULL) ? Description : L"Boot Manager Menu",
2630 DevicePath,
2631 NULL,
2632 0
2633 );
2634 ASSERT_EFI_ERROR (Status);
2635 FreePool (DevicePath);
2636 if (Description != NULL) {
2637 FreePool (Description);
2638 }
2639
2640 DEBUG_CODE (
2641 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2642 UINTN BootOptionCount;
2643
2644 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2645 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
2646 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2647 );
2648
2649 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
2650 }
2651
2652 /**
2653 Return the boot option corresponding to the Boot Manager Menu.
2654 It may automatically create one if the boot option hasn't been created yet.
2655
2656 @param BootOption Return the Boot Manager Menu.
2657
2658 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2659 @retval Status Return status of gRT->SetVariable (). BootOption still points
2660 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2661 **/
2662 EFI_STATUS
2663 EFIAPI
2664 EfiBootManagerGetBootManagerMenu (
2665 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2666 )
2667 {
2668 EFI_STATUS Status;
2669 UINTN BootOptionCount;
2670 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2671 UINTN Index;
2672 EFI_DEVICE_PATH_PROTOCOL *Node;
2673 EFI_HANDLE FvHandle;
2674
2675 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2676
2677 for (Index = 0; Index < BootOptionCount; Index++) {
2678 Node = BootOptions[Index].FilePath;
2679 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
2680 if (!EFI_ERROR (Status)) {
2681 if (CompareGuid (
2682 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
2683 PcdGetPtr (PcdBootManagerMenuFile)
2684 )
2685 ) {
2686 Status = EfiBootManagerInitializeLoadOption (
2687 BootOption,
2688 BootOptions[Index].OptionNumber,
2689 BootOptions[Index].OptionType,
2690 BootOptions[Index].Attributes,
2691 BootOptions[Index].Description,
2692 BootOptions[Index].FilePath,
2693 BootOptions[Index].OptionalData,
2694 BootOptions[Index].OptionalDataSize
2695 );
2696 ASSERT_EFI_ERROR (Status);
2697 break;
2698 }
2699 }
2700 }
2701
2702 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2703
2704 //
2705 // Automatically create the Boot#### for Boot Manager Menu when not found.
2706 //
2707 if (Index == BootOptionCount) {
2708 return BmRegisterBootManagerMenu (BootOption);
2709 } else {
2710 return EFI_SUCCESS;
2711 }
2712 }
2713