]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/UefiBootManagerLib: Separate boot description functions.
[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 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
19 EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = 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 mBmHardDriveBootVariableGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde } };
26 EFI_GUID mBmAutoCreateBootOptionGuid = { 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 } };
27
28 /**
29 The function registers the legacy boot support capabilities.
30
31 @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
32 @param LegacyBoot The function pointer to boot the legacy boot option.
33 **/
34 VOID
35 EFIAPI
36 EfiBootManagerRegisterLegacyBootSupport (
37 EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
38 EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
39 )
40 {
41 mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
42 mBmLegacyBoot = LegacyBoot;
43 }
44
45 /**
46 Return TRUE when the boot option is auto-created instead of manually added.
47
48 @param BootOption Pointer to the boot option to check.
49
50 @retval TRUE The boot option is auto-created.
51 @retval FALSE The boot option is manually added.
52 **/
53 BOOLEAN
54 BmIsAutoCreateBootOption (
55 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
56 )
57 {
58 if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
59 CompareGuid ((EFI_GUID *) BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
60 ) {
61 return TRUE;
62 } else {
63 return FALSE;
64 }
65 }
66
67 /**
68 Find the boot option in the NV storage and return the option number.
69
70 @param OptionToFind Boot option to be checked.
71
72 @return The option number of the found boot option.
73
74 **/
75 UINTN
76 BmFindBootOptionInVariable (
77 IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind
78 )
79 {
80 EFI_STATUS Status;
81 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
82 UINTN OptionNumber;
83 CHAR16 OptionName[BM_OPTION_NAME_LEN];
84 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
85 UINTN BootOptionCount;
86 UINTN Index;
87
88 OptionNumber = LoadOptionNumberUnassigned;
89
90 //
91 // Try to match the variable exactly if the option number is assigned
92 //
93 if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
94 UnicodeSPrint (
95 OptionName, sizeof (OptionName), L"%s%04x",
96 mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
97 );
98 Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
99
100 if (!EFI_ERROR (Status)) {
101 ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
102 if ((OptionToFind->Attributes == BootOption.Attributes) &&
103 (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
104 (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
105 (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
106 (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
107 ) {
108 OptionNumber = OptionToFind->OptionNumber;
109 }
110 EfiBootManagerFreeLoadOption (&BootOption);
111 }
112 }
113
114 //
115 // The option number assigned is either incorrect or unassigned.
116 //
117 if (OptionNumber == LoadOptionNumberUnassigned) {
118 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
119
120 Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
121 if (Index != -1) {
122 OptionNumber = BootOptions[Index].OptionNumber;
123 }
124
125 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
126 }
127
128 return OptionNumber;
129 }
130
131 /**
132 Get the file buffer using a Memory Mapped Device Path.
133
134 FV address may change across reboot. This routine promises the FV file device path is right.
135
136 @param FilePath The Memory Mapped Device Path to get the file buffer.
137 @param FullPath Receive the updated FV Device Path pointint to the file.
138 @param FileSize Receive the file buffer size.
139
140 @return The file buffer.
141 **/
142 VOID *
143 BmGetFileBufferByFvFilePath (
144 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
145 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
146 OUT UINTN *FileSize
147 )
148 {
149 EFI_STATUS Status;
150 UINTN Index;
151 EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
152 EFI_HANDLE FvHandle;
153 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
154 UINT32 AuthenticationStatus;
155 UINTN FvHandleCount;
156 EFI_HANDLE *FvHandles;
157 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
158 VOID *FileBuffer;
159
160 //
161 // Get the file buffer by using the exactly FilePath.
162 //
163 FvFileNode = FilePath;
164 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
165 if (!EFI_ERROR (Status)) {
166 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
167 if (FileBuffer != NULL) {
168 *FullPath = DuplicateDevicePath (FilePath);
169 }
170 return FileBuffer;
171 }
172
173 //
174 // Only wide match other FVs if it's a memory mapped FV file path.
175 //
176 if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {
177 return NULL;
178 }
179
180 FvFileNode = NextDevicePathNode (FilePath);
181
182 //
183 // Firstly find the FV file in current FV
184 //
185 gBS->HandleProtocol (
186 gImageHandle,
187 &gEfiLoadedImageProtocolGuid,
188 (VOID **) &LoadedImage
189 );
190 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
191 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
192 FreePool (NewDevicePath);
193
194 if (FileBuffer != NULL) {
195 return FileBuffer;
196 }
197
198 //
199 // Secondly find the FV file in all other FVs
200 //
201 gBS->LocateHandleBuffer (
202 ByProtocol,
203 &gEfiFirmwareVolume2ProtocolGuid,
204 NULL,
205 &FvHandleCount,
206 &FvHandles
207 );
208 for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
209 if (FvHandles[Index] == LoadedImage->DeviceHandle) {
210 //
211 // Skip current FV
212 //
213 continue;
214 }
215 NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
216 FileBuffer = BmGetFileBufferByFvFilePath (NewDevicePath, FullPath, FileSize);
217 FreePool (NewDevicePath);
218 }
219
220 if (FvHandles != NULL) {
221 FreePool (FvHandles);
222 }
223 return FileBuffer;
224 }
225
226 /**
227 Check if it's a Device Path pointing to FV file.
228
229 The function doesn't garentee the device path points to existing FV file.
230
231 @param DevicePath Input device path.
232
233 @retval TRUE The device path is a FV File Device Path.
234 @retval FALSE The device path is NOT a FV File Device Path.
235 **/
236 BOOLEAN
237 BmIsFvFilePath (
238 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
239 )
240 {
241 EFI_STATUS Status;
242 EFI_HANDLE Handle;
243 EFI_DEVICE_PATH_PROTOCOL *Node;
244
245 Node = DevicePath;
246 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);
247 if (!EFI_ERROR (Status)) {
248 return TRUE;
249 }
250
251 if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
252 DevicePath = NextDevicePathNode (DevicePath);
253 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
254 return IsDevicePathEnd (NextDevicePathNode (DevicePath));
255 }
256 }
257 return FALSE;
258 }
259
260 /**
261 Check whether a USB device match the specified USB Class device path. This
262 function follows "Load Option Processing" behavior in UEFI specification.
263
264 @param UsbIo USB I/O protocol associated with the USB device.
265 @param UsbClass The USB Class device path to match.
266
267 @retval TRUE The USB device match the USB Class device path.
268 @retval FALSE The USB device does not match the USB Class device path.
269
270 **/
271 BOOLEAN
272 BmMatchUsbClass (
273 IN EFI_USB_IO_PROTOCOL *UsbIo,
274 IN USB_CLASS_DEVICE_PATH *UsbClass
275 )
276 {
277 EFI_STATUS Status;
278 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
279 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
280 UINT8 DeviceClass;
281 UINT8 DeviceSubClass;
282 UINT8 DeviceProtocol;
283
284 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
285 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
286 return FALSE;
287 }
288
289 //
290 // Check Vendor Id and Product Id.
291 //
292 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
293 if (EFI_ERROR (Status)) {
294 return FALSE;
295 }
296
297 if ((UsbClass->VendorId != 0xffff) &&
298 (UsbClass->VendorId != DevDesc.IdVendor)) {
299 return FALSE;
300 }
301
302 if ((UsbClass->ProductId != 0xffff) &&
303 (UsbClass->ProductId != DevDesc.IdProduct)) {
304 return FALSE;
305 }
306
307 DeviceClass = DevDesc.DeviceClass;
308 DeviceSubClass = DevDesc.DeviceSubClass;
309 DeviceProtocol = DevDesc.DeviceProtocol;
310 if (DeviceClass == 0) {
311 //
312 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
313 // Protocol in Interface Descriptor instead.
314 //
315 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
316 if (EFI_ERROR (Status)) {
317 return FALSE;
318 }
319
320 DeviceClass = IfDesc.InterfaceClass;
321 DeviceSubClass = IfDesc.InterfaceSubClass;
322 DeviceProtocol = IfDesc.InterfaceProtocol;
323 }
324
325 //
326 // Check Class, SubClass and Protocol.
327 //
328 if ((UsbClass->DeviceClass != 0xff) &&
329 (UsbClass->DeviceClass != DeviceClass)) {
330 return FALSE;
331 }
332
333 if ((UsbClass->DeviceSubClass != 0xff) &&
334 (UsbClass->DeviceSubClass != DeviceSubClass)) {
335 return FALSE;
336 }
337
338 if ((UsbClass->DeviceProtocol != 0xff) &&
339 (UsbClass->DeviceProtocol != DeviceProtocol)) {
340 return FALSE;
341 }
342
343 return TRUE;
344 }
345
346 /**
347 Check whether a USB device match the specified USB WWID device path. This
348 function follows "Load Option Processing" behavior in UEFI specification.
349
350 @param UsbIo USB I/O protocol associated with the USB device.
351 @param UsbWwid The USB WWID device path to match.
352
353 @retval TRUE The USB device match the USB WWID device path.
354 @retval FALSE The USB device does not match the USB WWID device path.
355
356 **/
357 BOOLEAN
358 BmMatchUsbWwid (
359 IN EFI_USB_IO_PROTOCOL *UsbIo,
360 IN USB_WWID_DEVICE_PATH *UsbWwid
361 )
362 {
363 EFI_STATUS Status;
364 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
365 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
366 UINT16 *LangIdTable;
367 UINT16 TableSize;
368 UINT16 Index;
369 CHAR16 *CompareStr;
370 UINTN CompareLen;
371 CHAR16 *SerialNumberStr;
372 UINTN Length;
373
374 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
375 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) {
376 return FALSE;
377 }
378
379 //
380 // Check Vendor Id and Product Id.
381 //
382 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
383 if (EFI_ERROR (Status)) {
384 return FALSE;
385 }
386 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
387 (DevDesc.IdProduct != UsbWwid->ProductId)) {
388 return FALSE;
389 }
390
391 //
392 // Check Interface Number.
393 //
394 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
395 if (EFI_ERROR (Status)) {
396 return FALSE;
397 }
398 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
399 return FALSE;
400 }
401
402 //
403 // Check Serial Number.
404 //
405 if (DevDesc.StrSerialNumber == 0) {
406 return FALSE;
407 }
408
409 //
410 // Get all supported languages.
411 //
412 TableSize = 0;
413 LangIdTable = NULL;
414 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
415 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
416 return FALSE;
417 }
418
419 //
420 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
421 //
422 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
423 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
424 if (CompareStr[CompareLen - 1] == L'\0') {
425 CompareLen--;
426 }
427
428 //
429 // Compare serial number in each supported language.
430 //
431 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
432 SerialNumberStr = NULL;
433 Status = UsbIo->UsbGetStringDescriptor (
434 UsbIo,
435 LangIdTable[Index],
436 DevDesc.StrSerialNumber,
437 &SerialNumberStr
438 );
439 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
440 continue;
441 }
442
443 Length = StrLen (SerialNumberStr);
444 if ((Length >= CompareLen) &&
445 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
446 FreePool (SerialNumberStr);
447 return TRUE;
448 }
449
450 FreePool (SerialNumberStr);
451 }
452
453 return FALSE;
454 }
455
456 /**
457 Find a USB device which match the specified short-form device path start with
458 USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
459 will search in all USB devices of the platform. If ParentDevicePath is not NULL,
460 this function will only search in its child devices.
461
462 @param DevicePath The device path that contains USB Class or USB WWID device path.
463 @param ParentDevicePathSize The length of the device path before the USB Class or
464 USB WWID device path.
465 @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
466
467 @retval NULL The matched USB IO handles cannot be found.
468 @retval other The matched USB IO handles.
469
470 **/
471 EFI_HANDLE *
472 BmFindUsbDevice (
473 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
474 IN UINTN ParentDevicePathSize,
475 OUT UINTN *UsbIoHandleCount
476 )
477 {
478 EFI_STATUS Status;
479 EFI_HANDLE *UsbIoHandles;
480 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
481 EFI_USB_IO_PROTOCOL *UsbIo;
482 UINTN Index;
483 BOOLEAN Matched;
484
485 ASSERT (UsbIoHandleCount != NULL);
486
487 //
488 // Get all UsbIo Handles.
489 //
490 Status = gBS->LocateHandleBuffer (
491 ByProtocol,
492 &gEfiUsbIoProtocolGuid,
493 NULL,
494 UsbIoHandleCount,
495 &UsbIoHandles
496 );
497 if (EFI_ERROR (Status)) {
498 *UsbIoHandleCount = 0;
499 UsbIoHandles = NULL;
500 }
501
502 for (Index = 0; Index < *UsbIoHandleCount; ) {
503 //
504 // Get the Usb IO interface.
505 //
506 Status = gBS->HandleProtocol(
507 UsbIoHandles[Index],
508 &gEfiUsbIoProtocolGuid,
509 (VOID **) &UsbIo
510 );
511 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
512 Matched = FALSE;
513 if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
514
515 //
516 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
517 //
518 if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
519 if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize)) ||
520 BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ((UINTN) DevicePath + ParentDevicePathSize))) {
521 Matched = TRUE;
522 }
523 }
524 }
525
526 if (!Matched) {
527 (*UsbIoHandleCount) --;
528 CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
529 } else {
530 Index++;
531 }
532 }
533
534 return UsbIoHandles;
535 }
536
537 /**
538 Expand USB Class or USB WWID device path node to be full device path of a USB
539 device in platform.
540
541 This function support following 4 cases:
542 1) Boot Option device path starts with a USB Class or USB WWID device path,
543 and there is no Media FilePath device path in the end.
544 In this case, it will follow Removable Media Boot Behavior.
545 2) Boot Option device path starts with a USB Class or USB WWID device path,
546 and ended with Media FilePath device path.
547 3) Boot Option device path starts with a full device path to a USB Host Controller,
548 contains a USB Class or USB WWID device path node, while not ended with Media
549 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
550 4) Boot Option device path starts with a full device path to a USB Host Controller,
551 contains a USB Class or USB WWID device path node, and ended with Media
552 FilePath device path.
553
554 @param FilePath The device path pointing to a load option.
555 It could be a short-form device path.
556 @param FullPath Return the full device path of the load option after
557 short-form device path expanding.
558 Caller is responsible to free it.
559 @param FileSize Return the load option size.
560 @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
561
562 @return The load option buffer. Caller is responsible to free the memory.
563 **/
564 VOID *
565 BmExpandUsbDevicePath (
566 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
567 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
568 OUT UINTN *FileSize,
569 IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
570 )
571 {
572 UINTN ParentDevicePathSize;
573 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
574 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
575 EFI_HANDLE *Handles;
576 UINTN HandleCount;
577 UINTN Index;
578 VOID *FileBuffer;
579
580 ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
581 RemainingDevicePath = NextDevicePathNode (ShortformNode);
582 FileBuffer = NULL;
583 Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
584
585 for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
586 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
587 FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
588 FreePool (FullDevicePath);
589 }
590
591 if (Handles != NULL) {
592 FreePool (Handles);
593 }
594
595 return FileBuffer;
596 }
597
598 /**
599 Expand File-path device path node to be full device path in platform.
600
601 @param FilePath The device path pointing to a load option.
602 It could be a short-form device path.
603 @param FullPath Return the full device path of the load option after
604 short-form device path expanding.
605 Caller is responsible to free it.
606 @param FileSize Return the load option size.
607
608 @return The load option buffer. Caller is responsible to free the memory.
609 **/
610 VOID *
611 BmExpandFileDevicePath (
612 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
613 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
614 OUT UINTN *FileSize
615 )
616 {
617 EFI_STATUS Status;
618 UINTN Index;
619 UINTN HandleCount;
620 EFI_HANDLE *Handles;
621 EFI_BLOCK_IO_PROTOCOL *BlockIo;
622 UINTN MediaType;
623 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
624 VOID *FileBuffer;
625 UINT32 AuthenticationStatus;
626
627 EfiBootManagerConnectAll ();
628 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
629 if (EFI_ERROR (Status)) {
630 HandleCount = 0;
631 Handles = NULL;
632 }
633
634 //
635 // Enumerate all removable media devices followed by all fixed media devices,
636 // followed by media devices which don't layer on block io.
637 //
638 for (MediaType = 0; MediaType < 3; MediaType++) {
639 for (Index = 0; Index < HandleCount; Index++) {
640 Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);
641 if (EFI_ERROR (Status)) {
642 BlockIo = NULL;
643 }
644 if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||
645 (MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
646 (MediaType == 2 && BlockIo == NULL)
647 ) {
648 FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
649 FileBuffer = GetFileBufferByFilePath (TRUE, FullDevicePath, FileSize, &AuthenticationStatus);
650 if (FileBuffer != NULL) {
651 *FullPath = FullDevicePath;
652 FreePool (Handles);
653 return FileBuffer;
654 }
655 FreePool (FullDevicePath);
656 }
657 }
658 }
659
660 if (Handles != NULL) {
661 FreePool (Handles);
662 }
663
664 *FullPath = NULL;
665 return NULL;
666 }
667
668 /**
669 Expand URI device path node to be full device path in platform.
670
671 @param FilePath The device path pointing to a load option.
672 It could be a short-form device path.
673 @param FullPath Return the full device path of the load option after
674 short-form device path expanding.
675 Caller is responsible to free it.
676 @param FileSize Return the load option size.
677
678 @return The load option buffer. Caller is responsible to free the memory.
679 **/
680 VOID *
681 BmExpandUriDevicePath (
682 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
683 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
684 OUT UINTN *FileSize
685 )
686 {
687 EFI_STATUS Status;
688 UINTN Index;
689 UINTN HandleCount;
690 EFI_HANDLE *Handles;
691 EFI_LOAD_FILE_PROTOCOL *LoadFile;
692 VOID *FileBuffer;
693
694 EfiBootManagerConnectAll ();
695 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
696 if (EFI_ERROR (Status)) {
697 HandleCount = 0;
698 Handles = NULL;
699 }
700
701 FileBuffer = NULL;
702
703 for (Index = 0; Index < HandleCount; Index++) {
704 Status = gBS->HandleProtocol (Handles[Index], &gEfiLoadFileProtocolGuid, (VOID *) &LoadFile);
705 ASSERT_EFI_ERROR (Status);
706
707 FileBuffer = NULL;
708 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);
709 if (Status == EFI_BUFFER_TOO_SMALL) {
710 FileBuffer = AllocatePool (*FileSize);
711 if (FileBuffer == NULL) {
712 break;
713 }
714 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, FileSize, FileBuffer);
715 }
716
717 if (!EFI_ERROR (Status)) {
718 //
719 // LoadFile() returns a file buffer mapping to a file system.
720 //
721 if (Status == EFI_WARN_FILE_SYSTEM) {
722 return BmGetFileBufferFromLoadFileFileSystem (Handles[Index], FullPath, FileSize);
723 }
724
725 ASSERT (Status == EFI_SUCCESS);
726 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
727 break;
728 }
729
730 if (FileBuffer != NULL) {
731 FreePool (FileBuffer);
732 }
733 }
734
735 if (Handles != NULL) {
736 FreePool (Handles);
737 }
738
739 return FileBuffer;
740 }
741
742 /**
743 Save the partition DevicePath to the CachedDevicePath as the first instance.
744
745 @param CachedDevicePath The device path cache.
746 @param DevicePath The partition device path to be cached.
747 **/
748 VOID
749 BmCachePartitionDevicePath (
750 IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
751 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
752 )
753 {
754 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
755 UINTN Count;
756
757 if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
758 TempDevicePath = *CachedDevicePath;
759 *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
760 FreePool (TempDevicePath);
761 }
762
763 if (*CachedDevicePath == NULL) {
764 *CachedDevicePath = DuplicateDevicePath (DevicePath);
765 return;
766 }
767
768 TempDevicePath = *CachedDevicePath;
769 *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
770 if (TempDevicePath != NULL) {
771 FreePool (TempDevicePath);
772 }
773
774 //
775 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
776 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
777 //
778 Count = 0;
779 TempDevicePath = *CachedDevicePath;
780 while (!IsDevicePathEnd (TempDevicePath)) {
781 TempDevicePath = NextDevicePathNode (TempDevicePath);
782 //
783 // Parse one instance
784 //
785 while (!IsDevicePathEndType (TempDevicePath)) {
786 TempDevicePath = NextDevicePathNode (TempDevicePath);
787 }
788 Count++;
789 //
790 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
791 //
792 if (Count == 12) {
793 SetDevicePathEndNode (TempDevicePath);
794 break;
795 }
796 }
797 }
798
799 /**
800 Expand a device path that starts with a hard drive media device path node to be a
801 full device path that includes the full hardware path to the device. We need
802 to do this so it can be booted. As an optimization the front match (the part point
803 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
804 so a connect all is not required on every boot. All successful history device path
805 which point to partition node (the front part) will be saved.
806
807 @param FilePath The device path pointing to a load option.
808 It could be a short-form device path.
809 @param FullPath Return the full device path of the load option after
810 short-form device path expanding.
811 Caller is responsible to free it.
812 @param FileSize Return the load option size.
813
814 @return The load option buffer. Caller is responsible to free the memory.
815 **/
816 VOID *
817 BmExpandPartitionDevicePath (
818 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
819 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
820 OUT UINTN *FileSize
821 )
822 {
823 EFI_STATUS Status;
824 UINTN BlockIoHandleCount;
825 EFI_HANDLE *BlockIoBuffer;
826 VOID *FileBuffer;
827 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
828 UINTN Index;
829 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
830 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
831 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
832 UINTN CachedDevicePathSize;
833 BOOLEAN NeedAdjust;
834 EFI_DEVICE_PATH_PROTOCOL *Instance;
835 UINTN Size;
836
837 FileBuffer = NULL;
838 //
839 // Check if there is prestore 'HDDP' variable.
840 // If exist, search the front path which point to partition node in the variable instants.
841 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
842 //
843 GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
844
845 //
846 // Delete the invalid 'HDDP' variable.
847 //
848 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
849 FreePool (CachedDevicePath);
850 CachedDevicePath = NULL;
851 Status = gRT->SetVariable (
852 L"HDDP",
853 &mBmHardDriveBootVariableGuid,
854 0,
855 0,
856 NULL
857 );
858 ASSERT_EFI_ERROR (Status);
859 }
860
861 if (CachedDevicePath != NULL) {
862 TempNewDevicePath = CachedDevicePath;
863 NeedAdjust = FALSE;
864 do {
865 //
866 // Check every instance of the variable
867 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
868 // partial partition boot option. Second, check whether the instance could be connected.
869 //
870 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
871 if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
872 //
873 // Connect the device path instance, the device path point to hard drive media device path node
874 // e.g. ACPI() /PCI()/ATA()/Partition()
875 //
876 Status = EfiBootManagerConnectDevicePath (Instance, NULL);
877 if (!EFI_ERROR (Status)) {
878 TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
879 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
880 FreePool (TempDevicePath);
881
882 if (FileBuffer != NULL) {
883 //
884 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
885 //
886 if (NeedAdjust) {
887 BmCachePartitionDevicePath (&CachedDevicePath, Instance);
888 //
889 // Save the matching Device Path so we don't need to do a connect all next time
890 // Failing to save only impacts performance next time expanding the short-form device path
891 //
892 Status = gRT->SetVariable (
893 L"HDDP",
894 &mBmHardDriveBootVariableGuid,
895 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
896 GetDevicePathSize (CachedDevicePath),
897 CachedDevicePath
898 );
899 }
900
901 FreePool (Instance);
902 FreePool (CachedDevicePath);
903 return FileBuffer;
904 }
905 }
906 }
907 //
908 // Come here means the first instance is not matched
909 //
910 NeedAdjust = TRUE;
911 FreePool(Instance);
912 } while (TempNewDevicePath != NULL);
913 }
914
915 //
916 // If we get here we fail to find or 'HDDP' not exist, and now we need
917 // to search all devices in the system for a matched partition
918 //
919 EfiBootManagerConnectAll ();
920 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
921 if (EFI_ERROR (Status)) {
922 BlockIoHandleCount = 0;
923 BlockIoBuffer = NULL;
924 }
925 //
926 // Loop through all the device handles that support the BLOCK_IO Protocol
927 //
928 for (Index = 0; Index < BlockIoHandleCount; Index++) {
929 BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
930 if (BlockIoDevicePath == NULL) {
931 continue;
932 }
933
934 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
935 //
936 // Find the matched partition device path
937 //
938 TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
939 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
940 FreePool (TempDevicePath);
941
942 if (FileBuffer != NULL) {
943 BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
944
945 //
946 // Save the matching Device Path so we don't need to do a connect all next time
947 // Failing to save only impacts performance next time expanding the short-form device path
948 //
949 Status = gRT->SetVariable (
950 L"HDDP",
951 &mBmHardDriveBootVariableGuid,
952 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
953 GetDevicePathSize (CachedDevicePath),
954 CachedDevicePath
955 );
956
957 break;
958 }
959 }
960 }
961
962 if (CachedDevicePath != NULL) {
963 FreePool (CachedDevicePath);
964 }
965 if (BlockIoBuffer != NULL) {
966 FreePool (BlockIoBuffer);
967 }
968 return FileBuffer;
969 }
970
971 /**
972 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
973 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
974
975 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
976 @param FullPath Return the full device path pointing to the load option.
977 @param FileSize Return the size of the load option.
978
979 @return The load option buffer.
980 **/
981 VOID *
982 BmExpandMediaDevicePath (
983 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
984 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
985 OUT UINTN *FileSize
986 )
987 {
988 EFI_STATUS Status;
989 EFI_HANDLE Handle;
990 EFI_BLOCK_IO_PROTOCOL *BlockIo;
991 VOID *Buffer;
992 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
993 UINTN Size;
994 UINTN TempSize;
995 EFI_HANDLE *SimpleFileSystemHandles;
996 UINTN NumberSimpleFileSystemHandles;
997 UINTN Index;
998 VOID *FileBuffer;
999 UINT32 AuthenticationStatus;
1000
1001 //
1002 // Check whether the device is connected
1003 //
1004 TempDevicePath = DevicePath;
1005 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1006 if (!EFI_ERROR (Status)) {
1007 ASSERT (IsDevicePathEnd (TempDevicePath));
1008
1009 TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
1010 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
1011 if (FileBuffer == NULL) {
1012 FreePool (TempDevicePath);
1013 TempDevicePath = NULL;
1014 }
1015 *FullPath = TempDevicePath;
1016 return FileBuffer;
1017 }
1018
1019 //
1020 // For device boot option only pointing to the removable device handle,
1021 // should make sure all its children handles (its child partion or media handles) are created and connected.
1022 //
1023 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1024
1025 //
1026 // Issue a dummy read to the device to check for media change.
1027 // When the removable media is changed, any Block IO read/write will
1028 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1029 // returned. After the Block IO protocol is reinstalled, subsequent
1030 // Block IO read/write will success.
1031 //
1032 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1033 ASSERT_EFI_ERROR (Status);
1034 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1035 ASSERT_EFI_ERROR (Status);
1036 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1037 if (Buffer != NULL) {
1038 BlockIo->ReadBlocks (
1039 BlockIo,
1040 BlockIo->Media->MediaId,
1041 0,
1042 BlockIo->Media->BlockSize,
1043 Buffer
1044 );
1045 FreePool (Buffer);
1046 }
1047
1048 //
1049 // Detect the the default boot file from removable Media
1050 //
1051 FileBuffer = NULL;
1052 *FullPath = NULL;
1053 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
1054 gBS->LocateHandleBuffer (
1055 ByProtocol,
1056 &gEfiSimpleFileSystemProtocolGuid,
1057 NULL,
1058 &NumberSimpleFileSystemHandles,
1059 &SimpleFileSystemHandles
1060 );
1061 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1062 //
1063 // Get the device path size of SimpleFileSystem handle
1064 //
1065 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1066 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
1067 //
1068 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1069 //
1070 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
1071 TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
1072 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
1073 if (FileBuffer != NULL) {
1074 *FullPath = TempDevicePath;
1075 break;
1076 }
1077 FreePool (TempDevicePath);
1078 }
1079 }
1080
1081 if (SimpleFileSystemHandles != NULL) {
1082 FreePool (SimpleFileSystemHandles);
1083 }
1084
1085 return FileBuffer;
1086 }
1087
1088 /**
1089 Check whether Left and Right are the same without matching the specific
1090 device path data in IP device path and URI device path node.
1091
1092 @retval TRUE Left and Right are the same.
1093 @retval FALSE Left and Right are the different.
1094 **/
1095 BOOLEAN
1096 BmMatchHttpBootDevicePath (
1097 IN EFI_DEVICE_PATH_PROTOCOL *Left,
1098 IN EFI_DEVICE_PATH_PROTOCOL *Right
1099 )
1100 {
1101 for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
1102 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
1103 ) {
1104 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
1105 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
1106 return FALSE;
1107 }
1108
1109 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
1110 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
1111 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
1112 ) {
1113 return FALSE;
1114 }
1115 }
1116 }
1117 return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
1118 }
1119
1120 /**
1121 Get the file buffer from the file system produced by Load File instance.
1122
1123 @param LoadFileHandle The handle of LoadFile instance.
1124 @param FullPath Return the full device path pointing to the load option.
1125 @param FileSize Return the size of the load option.
1126
1127 @return The load option buffer.
1128 **/
1129 VOID *
1130 BmGetFileBufferFromLoadFileFileSystem (
1131 IN EFI_HANDLE LoadFileHandle,
1132 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1133 OUT UINTN *FileSize
1134 )
1135 {
1136 EFI_STATUS Status;
1137 EFI_HANDLE Handle;
1138 EFI_HANDLE *Handles;
1139 UINTN HandleCount;
1140 UINTN Index;
1141 EFI_DEVICE_PATH_PROTOCOL *Node;
1142
1143 Status = gBS->LocateHandleBuffer (
1144 ByProtocol,
1145 &gEfiBlockIoProtocolGuid,
1146 NULL,
1147 &HandleCount,
1148 &Handles
1149 );
1150 if (EFI_ERROR (Status)) {
1151 Handles = NULL;
1152 HandleCount = 0;
1153 }
1154
1155 Handle = NULL;
1156 for (Index = 0; Index < HandleCount; Index++) {
1157 Node = DevicePathFromHandle (Handles[Index]);
1158 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1159 if (!EFI_ERROR (Status) &&
1160 (Handle == LoadFileHandle) &&
1161 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
1162 Handle = Handles[Index];
1163 break;
1164 }
1165 }
1166
1167 if (Handles != NULL) {
1168 FreePool (Handles);
1169 }
1170
1171 if (Index != HandleCount) {
1172 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
1173 } else {
1174 return NULL;
1175 }
1176 }
1177
1178 /**
1179 Get the file buffer from Load File instance.
1180
1181 @param FilePath The media device path pointing to a LoadFile instance.
1182 @param FullPath Return the full device path pointing to the load option.
1183 @param FileSize Return the size of the load option.
1184
1185 @return The load option buffer.
1186 **/
1187 VOID *
1188 BmGetFileBufferFromLoadFile (
1189 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1190 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1191 OUT UINTN *FileSize
1192 )
1193 {
1194 EFI_STATUS Status;
1195 EFI_HANDLE Handle;
1196 VOID *FileBuffer;
1197 EFI_HANDLE *Handles;
1198 UINTN HandleCount;
1199 UINTN Index;
1200 EFI_DEVICE_PATH_PROTOCOL *Node;
1201 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1202 UINTN BufferSize;
1203
1204 //
1205 // Get file buffer from load file instance.
1206 //
1207 Node = FilePath;
1208 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1209 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1210 //
1211 // When wide match happens, pass full device path to LoadFile (),
1212 // otherwise, pass remaining device path to LoadFile ().
1213 //
1214 FilePath = Node;
1215 } else {
1216 Handle = NULL;
1217 //
1218 // Use wide match algorithm to find one when
1219 // cannot find a LoadFile instance to exactly match the FilePath
1220 //
1221 Status = gBS->LocateHandleBuffer (
1222 ByProtocol,
1223 &gEfiLoadFileProtocolGuid,
1224 NULL,
1225 &HandleCount,
1226 &Handles
1227 );
1228 if (EFI_ERROR (Status)) {
1229 Handles = NULL;
1230 HandleCount = 0;
1231 }
1232 for (Index = 0; Index < HandleCount; Index++) {
1233 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
1234 Handle = Handles[Index];
1235 break;
1236 }
1237 }
1238 if (Handles != NULL) {
1239 FreePool (Handles);
1240 }
1241 }
1242
1243 if (Handle == NULL) {
1244 return NULL;
1245 }
1246
1247 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **) &LoadFile);
1248 ASSERT_EFI_ERROR (Status);
1249
1250 BufferSize = 0;
1251 FileBuffer = NULL;
1252 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1253 if (Status == EFI_BUFFER_TOO_SMALL) {
1254 FileBuffer = AllocatePool (BufferSize);
1255 if (FileBuffer != NULL) {
1256 Status = EFI_SUCCESS;
1257 }
1258 }
1259
1260 if (!EFI_ERROR (Status)) {
1261 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1262 }
1263
1264 if (!EFI_ERROR (Status)) {
1265 //
1266 // LoadFile() returns a file buffer mapping to a file system.
1267 //
1268 if (Status == EFI_WARN_FILE_SYSTEM) {
1269 return BmGetFileBufferFromLoadFileFileSystem (Handle, FullPath, FileSize);
1270 }
1271
1272 ASSERT (Status == EFI_SUCCESS);
1273 //
1274 // LoadFile () may cause the device path of the Handle be updated.
1275 //
1276 *FullPath = DuplicateDevicePath (DevicePathFromHandle (Handle));
1277 *FileSize = BufferSize;
1278 return FileBuffer;
1279 } else {
1280 return NULL;
1281 }
1282 }
1283
1284 /**
1285 Get the load option by its device path.
1286
1287 @param FilePath The device path pointing to a load option.
1288 It could be a short-form device path.
1289 @param FullPath Return the full device path of the load option after
1290 short-form device path expanding.
1291 Caller is responsible to free it.
1292 @param FileSize Return the load option size.
1293
1294 @return The load option buffer. Caller is responsible to free the memory.
1295 **/
1296 VOID *
1297 BmGetLoadOptionBuffer (
1298 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1299 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1300 OUT UINTN *FileSize
1301 )
1302 {
1303 EFI_HANDLE Handle;
1304 VOID *FileBuffer;
1305 UINT32 AuthenticationStatus;
1306 EFI_DEVICE_PATH_PROTOCOL *Node;
1307 EFI_STATUS Status;
1308
1309 ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
1310
1311 EfiBootManagerConnectDevicePath (FilePath, NULL);
1312
1313 *FullPath = NULL;
1314 *FileSize = 0;
1315 FileBuffer = NULL;
1316
1317 //
1318 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1319 //
1320 Node = FilePath;
1321 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1322 if (EFI_ERROR (Status)) {
1323 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
1324 }
1325
1326 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1327 return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
1328 }
1329
1330 //
1331 // Expand the short-form device path to full device path
1332 //
1333 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1334 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
1335 //
1336 // Expand the Harddrive device path
1337 //
1338 return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
1339 } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1340 (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
1341 //
1342 // Expand the File-path device path
1343 //
1344 return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
1345 } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
1346 (DevicePathSubType (FilePath) == MSG_URI_DP)) {
1347 //
1348 // Expand the URI device path
1349 //
1350 return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
1351 } else {
1352 for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
1353 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
1354 ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
1355 break;
1356 }
1357 }
1358
1359 if (!IsDevicePathEnd (Node)) {
1360 //
1361 // Expand the USB WWID/Class device path
1362 //
1363 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1364 if ((FileBuffer == NULL) && (FilePath == Node)) {
1365 //
1366 // Boot Option device path starts with USB Class or USB WWID device path.
1367 // For Boot Option device path which doesn't begin with the USB Class or
1368 // USB WWID device path, it's not needed to connect again here.
1369 //
1370 BmConnectUsbShortFormDevicePath (FilePath);
1371 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1372 }
1373 return FileBuffer;
1374 }
1375 }
1376
1377 //
1378 // Get file buffer from FV file path.
1379 //
1380 if (BmIsFvFilePath (FilePath)) {
1381 return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
1382 }
1383
1384 //
1385 // Get file buffer from simple file system.
1386 //
1387 Node = FilePath;
1388 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1389 if (!EFI_ERROR (Status)) {
1390 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
1391 if (FileBuffer != NULL) {
1392 *FullPath = DuplicateDevicePath (FilePath);
1393 }
1394 return FileBuffer;
1395 }
1396
1397 return BmGetFileBufferFromLoadFile (FilePath, FullPath, FileSize);
1398 }
1399
1400 /**
1401 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1402 also signals the EFI ready to boot event. If the device path for the option
1403 starts with a BBS device path a legacy boot is attempted via the registered
1404 gLegacyBoot function. Short form device paths are also supported via this
1405 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1406 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1407 If the BootOption Device Path fails the removable media boot algorithm
1408 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1409 is tried per processor type)
1410
1411 @param BootOption Boot Option to try and boot.
1412 On return, BootOption->Status contains the boot status.
1413 EFI_SUCCESS BootOption was booted
1414 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1415 registered via EfiBootManagerInitialize().
1416 EFI_NOT_FOUND The BootOption was not found on the system
1417 !EFI_SUCCESS BootOption failed with this error status
1418
1419 **/
1420 VOID
1421 EFIAPI
1422 EfiBootManagerBoot (
1423 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1424 )
1425 {
1426 EFI_STATUS Status;
1427 EFI_HANDLE ImageHandle;
1428 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1429 UINT16 Uint16;
1430 UINTN OptionNumber;
1431 UINTN OriginalOptionNumber;
1432 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1433 EFI_DEVICE_PATH_PROTOCOL *Node;
1434 EFI_HANDLE FvHandle;
1435 VOID *FileBuffer;
1436 UINTN FileSize;
1437 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
1438 EFI_EVENT LegacyBootEvent;
1439
1440 if (BootOption == NULL) {
1441 return;
1442 }
1443
1444 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
1445 BootOption->Status = EFI_INVALID_PARAMETER;
1446 return;
1447 }
1448
1449 //
1450 // 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")
1451 //
1452 OptionNumber = BmFindBootOptionInVariable (BootOption);
1453 if (OptionNumber == LoadOptionNumberUnassigned) {
1454 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
1455 if (!EFI_ERROR (Status)) {
1456 //
1457 // Save the BootOption->OptionNumber to restore later
1458 //
1459 OptionNumber = Uint16;
1460 OriginalOptionNumber = BootOption->OptionNumber;
1461 BootOption->OptionNumber = OptionNumber;
1462 Status = EfiBootManagerLoadOptionToVariable (BootOption);
1463 BootOption->OptionNumber = OriginalOptionNumber;
1464 }
1465
1466 if (EFI_ERROR (Status)) {
1467 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
1468 BootOption->Status = Status;
1469 return ;
1470 }
1471 }
1472
1473 //
1474 // 2. Set BootCurrent
1475 //
1476 Uint16 = (UINT16) OptionNumber;
1477 BmSetVariableAndReportStatusCodeOnError (
1478 L"BootCurrent",
1479 &gEfiGlobalVariableGuid,
1480 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1481 sizeof (UINT16),
1482 &Uint16
1483 );
1484
1485 //
1486 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1487 // the boot option.
1488 //
1489 Node = BootOption->FilePath;
1490 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
1491 if (!EFI_ERROR (Status) && CompareGuid (
1492 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
1493 PcdGetPtr (PcdBootManagerMenuFile)
1494 )) {
1495 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
1496 BmStopHotkeyService (NULL, NULL);
1497 } else {
1498 EfiSignalEventReadyToBoot();
1499 //
1500 // Report Status Code to indicate ReadyToBoot was signalled
1501 //
1502 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
1503 //
1504 // 4. Repair system through DriverHealth protocol
1505 //
1506 BmRepairAllControllers ();
1507 }
1508
1509 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1510
1511 //
1512 // 5. Load EFI boot option to ImageHandle
1513 //
1514 ImageHandle = NULL;
1515 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
1516 Status = EFI_NOT_FOUND;
1517 FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
1518 DEBUG_CODE (
1519 if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
1520 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
1521 BmPrintDp (BootOption->FilePath);
1522 DEBUG ((EFI_D_INFO, " -> "));
1523 BmPrintDp (FilePath);
1524 DEBUG ((EFI_D_INFO, "\n"));
1525 }
1526 );
1527 if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
1528 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
1529 Status = gBS->LoadImage (
1530 TRUE,
1531 gImageHandle,
1532 FilePath,
1533 FileBuffer,
1534 FileSize,
1535 &ImageHandle
1536 );
1537 }
1538 if (FileBuffer != NULL) {
1539 FreePool (FileBuffer);
1540 }
1541 if (FilePath != NULL) {
1542 FreePool (FilePath);
1543 }
1544
1545 if (EFI_ERROR (Status)) {
1546 //
1547 // Report Status Code to indicate that the failure to load boot option
1548 //
1549 REPORT_STATUS_CODE (
1550 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1551 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
1552 );
1553 BootOption->Status = Status;
1554 return;
1555 }
1556 }
1557
1558 //
1559 // 6. Adjust the different type memory page number just before booting
1560 // and save the updated info into the variable for next boot to use
1561 //
1562 BmSetMemoryTypeInformationVariable (
1563 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
1564 );
1565
1566 DEBUG_CODE_BEGIN();
1567 if (BootOption->Description == NULL) {
1568 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
1569 } else {
1570 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
1571 }
1572 DEBUG_CODE_END();
1573
1574 //
1575 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1576 // Write boot to OS performance data for Legacy boot
1577 //
1578 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
1579 if (mBmLegacyBoot != NULL) {
1580 //
1581 // Write boot to OS performance data for legacy boot.
1582 //
1583 PERF_CODE (
1584 //
1585 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1586 //
1587 Status = EfiCreateEventLegacyBootEx(
1588 TPL_NOTIFY,
1589 BmWriteBootToOsPerformanceData,
1590 NULL,
1591 &LegacyBootEvent
1592 );
1593 ASSERT_EFI_ERROR (Status);
1594 );
1595
1596 mBmLegacyBoot (BootOption);
1597 } else {
1598 BootOption->Status = EFI_UNSUPPORTED;
1599 }
1600
1601 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1602 return;
1603 }
1604
1605 //
1606 // Provide the image with its load options
1607 //
1608 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1609 ASSERT_EFI_ERROR (Status);
1610
1611 if (!BmIsAutoCreateBootOption (BootOption)) {
1612 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
1613 ImageInfo->LoadOptions = BootOption->OptionalData;
1614 }
1615
1616 //
1617 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1618 //
1619 ImageInfo->ParentHandle = NULL;
1620
1621 //
1622 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1623 //
1624 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1625
1626 //
1627 // Write boot to OS performance data for UEFI boot
1628 //
1629 PERF_CODE (
1630 BmWriteBootToOsPerformanceData (NULL, NULL);
1631 );
1632
1633 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
1634
1635 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
1636 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
1637 BootOption->Status = Status;
1638 if (EFI_ERROR (Status)) {
1639 //
1640 // Report Status Code to indicate that boot failure
1641 //
1642 REPORT_STATUS_CODE (
1643 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1644 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
1645 );
1646 }
1647 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1648
1649 //
1650 // Clear the Watchdog Timer after the image returns
1651 //
1652 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1653
1654 //
1655 // Set Logo status invalid after trying one boot option
1656 //
1657 BootLogo = NULL;
1658 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
1659 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
1660 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
1661 ASSERT_EFI_ERROR (Status);
1662 }
1663
1664 //
1665 // Clear Boot Current
1666 //
1667 Status = gRT->SetVariable (
1668 L"BootCurrent",
1669 &gEfiGlobalVariableGuid,
1670 0,
1671 0,
1672 NULL
1673 );
1674 //
1675 // Deleting variable with current variable implementation shouldn't fail.
1676 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1677 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1678 //
1679 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
1680 }
1681
1682 /**
1683 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1684 instances, has the same partition node with HardDriveDevicePath device path
1685
1686 @param BlockIoDevicePath Multi device path instances which need to check
1687 @param HardDriveDevicePath A device path which starts with a hard drive media
1688 device path.
1689
1690 @retval TRUE There is a matched device path instance.
1691 @retval FALSE There is no matched device path instance.
1692
1693 **/
1694 BOOLEAN
1695 BmMatchPartitionDevicePathNode (
1696 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
1697 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
1698 )
1699 {
1700 HARDDRIVE_DEVICE_PATH *Node;
1701
1702 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
1703 return FALSE;
1704 }
1705
1706 //
1707 // find the partition device path node
1708 //
1709 while (!IsDevicePathEnd (BlockIoDevicePath)) {
1710 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
1711 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
1712 ) {
1713 break;
1714 }
1715
1716 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
1717 }
1718
1719 if (IsDevicePathEnd (BlockIoDevicePath)) {
1720 return FALSE;
1721 }
1722
1723 //
1724 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1725 //
1726 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
1727
1728 //
1729 // Match Signature and PartitionNumber.
1730 // Unused bytes in Signature are initiaized with zeros.
1731 //
1732 return (BOOLEAN) (
1733 (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
1734 (Node->MBRType == HardDriveDevicePath->MBRType) &&
1735 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
1736 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
1737 );
1738 }
1739
1740 /**
1741 Emuerate all possible bootable medias in the following order:
1742 1. Removable BlockIo - The boot option only points to the removable media
1743 device, like USB key, DVD, Floppy etc.
1744 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1745 like HardDisk.
1746 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1747 SimpleFileSystem Protocol, but not supporting BlockIo
1748 protocol.
1749 4. LoadFile - The boot option points to the media supporting
1750 LoadFile protocol.
1751 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1752
1753 @param BootOptionCount Return the boot option count which has been found.
1754
1755 @retval Pointer to the boot option array.
1756 **/
1757 EFI_BOOT_MANAGER_LOAD_OPTION *
1758 BmEnumerateBootOptions (
1759 UINTN *BootOptionCount
1760 )
1761 {
1762 EFI_STATUS Status;
1763 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1764 UINTN HandleCount;
1765 EFI_HANDLE *Handles;
1766 EFI_BLOCK_IO_PROTOCOL *BlkIo;
1767 UINTN Removable;
1768 UINTN Index;
1769 CHAR16 *Description;
1770
1771 ASSERT (BootOptionCount != NULL);
1772
1773 *BootOptionCount = 0;
1774 BootOptions = NULL;
1775
1776 //
1777 // Parse removable block io followed by fixed block io
1778 //
1779 gBS->LocateHandleBuffer (
1780 ByProtocol,
1781 &gEfiBlockIoProtocolGuid,
1782 NULL,
1783 &HandleCount,
1784 &Handles
1785 );
1786
1787 for (Removable = 0; Removable < 2; Removable++) {
1788 for (Index = 0; Index < HandleCount; Index++) {
1789 Status = gBS->HandleProtocol (
1790 Handles[Index],
1791 &gEfiBlockIoProtocolGuid,
1792 (VOID **) &BlkIo
1793 );
1794 if (EFI_ERROR (Status)) {
1795 continue;
1796 }
1797
1798 //
1799 // Skip the logical partitions
1800 //
1801 if (BlkIo->Media->LogicalPartition) {
1802 continue;
1803 }
1804
1805 //
1806 // Skip the fixed block io then the removable block io
1807 //
1808 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
1809 continue;
1810 }
1811
1812 Description = BmGetBootDescription (Handles[Index]);
1813 BootOptions = ReallocatePool (
1814 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1815 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1816 BootOptions
1817 );
1818 ASSERT (BootOptions != NULL);
1819
1820 Status = EfiBootManagerInitializeLoadOption (
1821 &BootOptions[(*BootOptionCount)++],
1822 LoadOptionNumberUnassigned,
1823 LoadOptionTypeBoot,
1824 LOAD_OPTION_ACTIVE,
1825 Description,
1826 DevicePathFromHandle (Handles[Index]),
1827 NULL,
1828 0
1829 );
1830 ASSERT_EFI_ERROR (Status);
1831
1832 FreePool (Description);
1833 }
1834 }
1835
1836 if (HandleCount != 0) {
1837 FreePool (Handles);
1838 }
1839
1840 //
1841 // Parse simple file system not based on block io
1842 //
1843 gBS->LocateHandleBuffer (
1844 ByProtocol,
1845 &gEfiSimpleFileSystemProtocolGuid,
1846 NULL,
1847 &HandleCount,
1848 &Handles
1849 );
1850 for (Index = 0; Index < HandleCount; Index++) {
1851 Status = gBS->HandleProtocol (
1852 Handles[Index],
1853 &gEfiBlockIoProtocolGuid,
1854 (VOID **) &BlkIo
1855 );
1856 if (!EFI_ERROR (Status)) {
1857 //
1858 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1859 //
1860 continue;
1861 }
1862 Description = BmGetBootDescription (Handles[Index]);
1863 BootOptions = ReallocatePool (
1864 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1865 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1866 BootOptions
1867 );
1868 ASSERT (BootOptions != NULL);
1869
1870 Status = EfiBootManagerInitializeLoadOption (
1871 &BootOptions[(*BootOptionCount)++],
1872 LoadOptionNumberUnassigned,
1873 LoadOptionTypeBoot,
1874 LOAD_OPTION_ACTIVE,
1875 Description,
1876 DevicePathFromHandle (Handles[Index]),
1877 NULL,
1878 0
1879 );
1880 ASSERT_EFI_ERROR (Status);
1881 FreePool (Description);
1882 }
1883
1884 if (HandleCount != 0) {
1885 FreePool (Handles);
1886 }
1887
1888 //
1889 // Parse load file, assuming UEFI Network boot option
1890 //
1891 gBS->LocateHandleBuffer (
1892 ByProtocol,
1893 &gEfiLoadFileProtocolGuid,
1894 NULL,
1895 &HandleCount,
1896 &Handles
1897 );
1898 for (Index = 0; Index < HandleCount; Index++) {
1899
1900 Description = BmGetBootDescription (Handles[Index]);
1901 BootOptions = ReallocatePool (
1902 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1903 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1904 BootOptions
1905 );
1906 ASSERT (BootOptions != NULL);
1907
1908 Status = EfiBootManagerInitializeLoadOption (
1909 &BootOptions[(*BootOptionCount)++],
1910 LoadOptionNumberUnassigned,
1911 LoadOptionTypeBoot,
1912 LOAD_OPTION_ACTIVE,
1913 Description,
1914 DevicePathFromHandle (Handles[Index]),
1915 NULL,
1916 0
1917 );
1918 ASSERT_EFI_ERROR (Status);
1919 FreePool (Description);
1920 }
1921
1922 if (HandleCount != 0) {
1923 FreePool (Handles);
1924 }
1925
1926 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
1927 return BootOptions;
1928 }
1929
1930 /**
1931 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
1932 **/
1933 VOID
1934 EFIAPI
1935 EfiBootManagerRefreshAllBootOption (
1936 VOID
1937 )
1938 {
1939 EFI_STATUS Status;
1940 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
1941 UINTN NvBootOptionCount;
1942 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1943 UINTN BootOptionCount;
1944 UINTN Index;
1945
1946 //
1947 // Optionally refresh the legacy boot option
1948 //
1949 if (mBmRefreshLegacyBootOption != NULL) {
1950 mBmRefreshLegacyBootOption ();
1951 }
1952
1953 BootOptions = BmEnumerateBootOptions (&BootOptionCount);
1954 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
1955
1956 //
1957 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
1958 //
1959 for (Index = 0; Index < BootOptionCount; Index++) {
1960 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
1961 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
1962 }
1963
1964 //
1965 // Remove invalid EFI boot options from NV
1966 //
1967 for (Index = 0; Index < NvBootOptionCount; Index++) {
1968 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
1969 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
1970 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
1971 ) {
1972 //
1973 // Only check those added by BDS
1974 // so that the boot options added by end-user or OS installer won't be deleted
1975 //
1976 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
1977 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
1978 //
1979 // Deleting variable with current variable implementation shouldn't fail.
1980 //
1981 ASSERT_EFI_ERROR (Status);
1982 }
1983 }
1984 }
1985
1986 //
1987 // Add new EFI boot options to NV
1988 //
1989 for (Index = 0; Index < BootOptionCount; Index++) {
1990 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
1991 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
1992 //
1993 // Try best to add the boot options so continue upon failure.
1994 //
1995 }
1996 }
1997
1998 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
1999 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
2000 }
2001
2002 /**
2003 This function is called to create the boot option for the Boot Manager Menu.
2004
2005 The Boot Manager Menu is shown after successfully booting a boot option.
2006 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2007
2008 @param BootOption Return the boot option of the Boot Manager Menu
2009
2010 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2011 @retval Status Return status of gRT->SetVariable (). BootOption still points
2012 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2013 **/
2014 EFI_STATUS
2015 BmRegisterBootManagerMenu (
2016 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2017 )
2018 {
2019 EFI_STATUS Status;
2020 CHAR16 *Description;
2021 UINTN DescriptionLength;
2022 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2023 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2024 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
2025
2026 Status = GetSectionFromFv (
2027 PcdGetPtr (PcdBootManagerMenuFile),
2028 EFI_SECTION_USER_INTERFACE,
2029 0,
2030 (VOID **) &Description,
2031 &DescriptionLength
2032 );
2033 if (EFI_ERROR (Status)) {
2034 Description = NULL;
2035 }
2036
2037 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
2038 Status = gBS->HandleProtocol (
2039 gImageHandle,
2040 &gEfiLoadedImageProtocolGuid,
2041 (VOID **) &LoadedImage
2042 );
2043 ASSERT_EFI_ERROR (Status);
2044 DevicePath = AppendDevicePathNode (
2045 DevicePathFromHandle (LoadedImage->DeviceHandle),
2046 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
2047 );
2048 ASSERT (DevicePath != NULL);
2049
2050 Status = EfiBootManagerInitializeLoadOption (
2051 BootOption,
2052 LoadOptionNumberUnassigned,
2053 LoadOptionTypeBoot,
2054 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
2055 (Description != NULL) ? Description : L"Boot Manager Menu",
2056 DevicePath,
2057 NULL,
2058 0
2059 );
2060 ASSERT_EFI_ERROR (Status);
2061 FreePool (DevicePath);
2062 if (Description != NULL) {
2063 FreePool (Description);
2064 }
2065
2066 DEBUG_CODE (
2067 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2068 UINTN BootOptionCount;
2069
2070 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2071 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
2072 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2073 );
2074
2075 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
2076 }
2077
2078 /**
2079 Return the boot option corresponding to the Boot Manager Menu.
2080 It may automatically create one if the boot option hasn't been created yet.
2081
2082 @param BootOption Return the Boot Manager Menu.
2083
2084 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2085 @retval Status Return status of gRT->SetVariable (). BootOption still points
2086 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2087 **/
2088 EFI_STATUS
2089 EFIAPI
2090 EfiBootManagerGetBootManagerMenu (
2091 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2092 )
2093 {
2094 EFI_STATUS Status;
2095 UINTN BootOptionCount;
2096 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2097 UINTN Index;
2098 EFI_DEVICE_PATH_PROTOCOL *Node;
2099 EFI_HANDLE FvHandle;
2100
2101 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2102
2103 for (Index = 0; Index < BootOptionCount; Index++) {
2104 Node = BootOptions[Index].FilePath;
2105 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
2106 if (!EFI_ERROR (Status)) {
2107 if (CompareGuid (
2108 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
2109 PcdGetPtr (PcdBootManagerMenuFile)
2110 )
2111 ) {
2112 Status = EfiBootManagerInitializeLoadOption (
2113 BootOption,
2114 BootOptions[Index].OptionNumber,
2115 BootOptions[Index].OptionType,
2116 BootOptions[Index].Attributes,
2117 BootOptions[Index].Description,
2118 BootOptions[Index].FilePath,
2119 BootOptions[Index].OptionalData,
2120 BootOptions[Index].OptionalDataSize
2121 );
2122 ASSERT_EFI_ERROR (Status);
2123 break;
2124 }
2125 }
2126 }
2127
2128 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2129
2130 //
2131 // Automatically create the Boot#### for Boot Manager Menu when not found.
2132 //
2133 if (Index == BootOptionCount) {
2134 return BmRegisterBootManagerMenu (BootOption);
2135 } else {
2136 return EFI_SUCCESS;
2137 }
2138 }
2139