]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
MdeModulePkg/Bds: Allocate reserved memory for RAM Disk boot media
[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 VOID *FileBuffer;
692
693 EfiBootManagerConnectAll ();
694 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
695 if (EFI_ERROR (Status)) {
696 HandleCount = 0;
697 Handles = NULL;
698 }
699
700 for (Index = 0; Index < HandleCount; Index++) {
701 FileBuffer = BmGetFileBufferFromLoadFile (Handles[Index], FilePath, FullPath, FileSize);
702 if (FileBuffer != NULL) {
703 break;
704 }
705 }
706
707 if (Handles != NULL) {
708 FreePool (Handles);
709 }
710
711 return FileBuffer;
712 }
713
714 /**
715 Save the partition DevicePath to the CachedDevicePath as the first instance.
716
717 @param CachedDevicePath The device path cache.
718 @param DevicePath The partition device path to be cached.
719 **/
720 VOID
721 BmCachePartitionDevicePath (
722 IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
723 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
724 )
725 {
726 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
727 UINTN Count;
728
729 if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
730 TempDevicePath = *CachedDevicePath;
731 *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
732 FreePool (TempDevicePath);
733 }
734
735 if (*CachedDevicePath == NULL) {
736 *CachedDevicePath = DuplicateDevicePath (DevicePath);
737 return;
738 }
739
740 TempDevicePath = *CachedDevicePath;
741 *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
742 if (TempDevicePath != NULL) {
743 FreePool (TempDevicePath);
744 }
745
746 //
747 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
748 // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
749 //
750 Count = 0;
751 TempDevicePath = *CachedDevicePath;
752 while (!IsDevicePathEnd (TempDevicePath)) {
753 TempDevicePath = NextDevicePathNode (TempDevicePath);
754 //
755 // Parse one instance
756 //
757 while (!IsDevicePathEndType (TempDevicePath)) {
758 TempDevicePath = NextDevicePathNode (TempDevicePath);
759 }
760 Count++;
761 //
762 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
763 //
764 if (Count == 12) {
765 SetDevicePathEndNode (TempDevicePath);
766 break;
767 }
768 }
769 }
770
771 /**
772 Expand a device path that starts with a hard drive media device path node to be a
773 full device path that includes the full hardware path to the device. We need
774 to do this so it can be booted. As an optimization the front match (the part point
775 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
776 so a connect all is not required on every boot. All successful history device path
777 which point to partition node (the front part) will be saved.
778
779 @param FilePath The device path pointing to a load option.
780 It could be a short-form device path.
781 @param FullPath Return the full device path of the load option after
782 short-form device path expanding.
783 Caller is responsible to free it.
784 @param FileSize Return the load option size.
785
786 @return The load option buffer. Caller is responsible to free the memory.
787 **/
788 VOID *
789 BmExpandPartitionDevicePath (
790 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
791 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
792 OUT UINTN *FileSize
793 )
794 {
795 EFI_STATUS Status;
796 UINTN BlockIoHandleCount;
797 EFI_HANDLE *BlockIoBuffer;
798 VOID *FileBuffer;
799 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
800 UINTN Index;
801 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
802 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
803 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
804 UINTN CachedDevicePathSize;
805 BOOLEAN NeedAdjust;
806 EFI_DEVICE_PATH_PROTOCOL *Instance;
807 UINTN Size;
808
809 FileBuffer = NULL;
810 //
811 // Check if there is prestore 'HDDP' variable.
812 // If exist, search the front path which point to partition node in the variable instants.
813 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
814 //
815 GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **) &CachedDevicePath, &CachedDevicePathSize);
816
817 //
818 // Delete the invalid 'HDDP' variable.
819 //
820 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
821 FreePool (CachedDevicePath);
822 CachedDevicePath = NULL;
823 Status = gRT->SetVariable (
824 L"HDDP",
825 &mBmHardDriveBootVariableGuid,
826 0,
827 0,
828 NULL
829 );
830 ASSERT_EFI_ERROR (Status);
831 }
832
833 if (CachedDevicePath != NULL) {
834 TempNewDevicePath = CachedDevicePath;
835 NeedAdjust = FALSE;
836 do {
837 //
838 // Check every instance of the variable
839 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
840 // partial partition boot option. Second, check whether the instance could be connected.
841 //
842 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
843 if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
844 //
845 // Connect the device path instance, the device path point to hard drive media device path node
846 // e.g. ACPI() /PCI()/ATA()/Partition()
847 //
848 Status = EfiBootManagerConnectDevicePath (Instance, NULL);
849 if (!EFI_ERROR (Status)) {
850 TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
851 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
852 FreePool (TempDevicePath);
853
854 if (FileBuffer != NULL) {
855 //
856 // Adjust the 'HDDP' instances sequence if the matched one is not first one.
857 //
858 if (NeedAdjust) {
859 BmCachePartitionDevicePath (&CachedDevicePath, Instance);
860 //
861 // Save the matching Device Path so we don't need to do a connect all next time
862 // Failing to save only impacts performance next time expanding the short-form device path
863 //
864 Status = gRT->SetVariable (
865 L"HDDP",
866 &mBmHardDriveBootVariableGuid,
867 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
868 GetDevicePathSize (CachedDevicePath),
869 CachedDevicePath
870 );
871 }
872
873 FreePool (Instance);
874 FreePool (CachedDevicePath);
875 return FileBuffer;
876 }
877 }
878 }
879 //
880 // Come here means the first instance is not matched
881 //
882 NeedAdjust = TRUE;
883 FreePool(Instance);
884 } while (TempNewDevicePath != NULL);
885 }
886
887 //
888 // If we get here we fail to find or 'HDDP' not exist, and now we need
889 // to search all devices in the system for a matched partition
890 //
891 EfiBootManagerConnectAll ();
892 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
893 if (EFI_ERROR (Status)) {
894 BlockIoHandleCount = 0;
895 BlockIoBuffer = NULL;
896 }
897 //
898 // Loop through all the device handles that support the BLOCK_IO Protocol
899 //
900 for (Index = 0; Index < BlockIoHandleCount; Index++) {
901 BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
902 if (BlockIoDevicePath == NULL) {
903 continue;
904 }
905
906 if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
907 //
908 // Find the matched partition device path
909 //
910 TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
911 FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
912 FreePool (TempDevicePath);
913
914 if (FileBuffer != NULL) {
915 BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
916
917 //
918 // Save the matching Device Path so we don't need to do a connect all next time
919 // Failing to save only impacts performance next time expanding the short-form device path
920 //
921 Status = gRT->SetVariable (
922 L"HDDP",
923 &mBmHardDriveBootVariableGuid,
924 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
925 GetDevicePathSize (CachedDevicePath),
926 CachedDevicePath
927 );
928
929 break;
930 }
931 }
932 }
933
934 if (CachedDevicePath != NULL) {
935 FreePool (CachedDevicePath);
936 }
937 if (BlockIoBuffer != NULL) {
938 FreePool (BlockIoBuffer);
939 }
940 return FileBuffer;
941 }
942
943 /**
944 Expand the media device path which points to a BlockIo or SimpleFileSystem instance
945 by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
946
947 @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
948 @param FullPath Return the full device path pointing to the load option.
949 @param FileSize Return the size of the load option.
950
951 @return The load option buffer.
952 **/
953 VOID *
954 BmExpandMediaDevicePath (
955 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
956 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
957 OUT UINTN *FileSize
958 )
959 {
960 EFI_STATUS Status;
961 EFI_HANDLE Handle;
962 EFI_BLOCK_IO_PROTOCOL *BlockIo;
963 VOID *Buffer;
964 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
965 UINTN Size;
966 UINTN TempSize;
967 EFI_HANDLE *SimpleFileSystemHandles;
968 UINTN NumberSimpleFileSystemHandles;
969 UINTN Index;
970 VOID *FileBuffer;
971 UINT32 AuthenticationStatus;
972
973 //
974 // Check whether the device is connected
975 //
976 TempDevicePath = DevicePath;
977 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
978 if (!EFI_ERROR (Status)) {
979 ASSERT (IsDevicePathEnd (TempDevicePath));
980
981 TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
982 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
983 if (FileBuffer == NULL) {
984 FreePool (TempDevicePath);
985 TempDevicePath = NULL;
986 }
987 *FullPath = TempDevicePath;
988 return FileBuffer;
989 }
990
991 //
992 // For device boot option only pointing to the removable device handle,
993 // should make sure all its children handles (its child partion or media handles) are created and connected.
994 //
995 gBS->ConnectController (Handle, NULL, NULL, TRUE);
996
997 //
998 // Issue a dummy read to the device to check for media change.
999 // When the removable media is changed, any Block IO read/write will
1000 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1001 // returned. After the Block IO protocol is reinstalled, subsequent
1002 // Block IO read/write will success.
1003 //
1004 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1005 ASSERT_EFI_ERROR (Status);
1006 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1007 ASSERT_EFI_ERROR (Status);
1008 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1009 if (Buffer != NULL) {
1010 BlockIo->ReadBlocks (
1011 BlockIo,
1012 BlockIo->Media->MediaId,
1013 0,
1014 BlockIo->Media->BlockSize,
1015 Buffer
1016 );
1017 FreePool (Buffer);
1018 }
1019
1020 //
1021 // Detect the the default boot file from removable Media
1022 //
1023 FileBuffer = NULL;
1024 *FullPath = NULL;
1025 Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
1026 gBS->LocateHandleBuffer (
1027 ByProtocol,
1028 &gEfiSimpleFileSystemProtocolGuid,
1029 NULL,
1030 &NumberSimpleFileSystemHandles,
1031 &SimpleFileSystemHandles
1032 );
1033 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1034 //
1035 // Get the device path size of SimpleFileSystem handle
1036 //
1037 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1038 TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
1039 //
1040 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1041 //
1042 if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
1043 TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
1044 FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
1045 if (FileBuffer != NULL) {
1046 *FullPath = TempDevicePath;
1047 break;
1048 }
1049 FreePool (TempDevicePath);
1050 }
1051 }
1052
1053 if (SimpleFileSystemHandles != NULL) {
1054 FreePool (SimpleFileSystemHandles);
1055 }
1056
1057 return FileBuffer;
1058 }
1059
1060 /**
1061 Check whether Left and Right are the same without matching the specific
1062 device path data in IP device path and URI device path node.
1063
1064 @retval TRUE Left and Right are the same.
1065 @retval FALSE Left and Right are the different.
1066 **/
1067 BOOLEAN
1068 BmMatchHttpBootDevicePath (
1069 IN EFI_DEVICE_PATH_PROTOCOL *Left,
1070 IN EFI_DEVICE_PATH_PROTOCOL *Right
1071 )
1072 {
1073 for (; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
1074 ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
1075 ) {
1076 if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
1077 if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
1078 return FALSE;
1079 }
1080
1081 if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
1082 ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
1083 ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
1084 ) {
1085 return FALSE;
1086 }
1087 }
1088 }
1089 return (BOOLEAN) (IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
1090 }
1091
1092 /**
1093 Get the file buffer from the file system produced by Load File instance.
1094
1095 @param LoadFileHandle The handle of LoadFile instance.
1096 @param FullPath Return the full device path pointing to the load option.
1097 @param FileSize Return the size of the load option.
1098
1099 @return The load option buffer.
1100 **/
1101 VOID *
1102 BmGetFileBufferFromLoadFileSystem (
1103 IN EFI_HANDLE LoadFileHandle,
1104 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1105 OUT UINTN *FileSize
1106 )
1107 {
1108 EFI_STATUS Status;
1109 EFI_HANDLE Handle;
1110 EFI_HANDLE *Handles;
1111 UINTN HandleCount;
1112 UINTN Index;
1113 EFI_DEVICE_PATH_PROTOCOL *Node;
1114
1115 Status = gBS->LocateHandleBuffer (
1116 ByProtocol,
1117 &gEfiBlockIoProtocolGuid,
1118 NULL,
1119 &HandleCount,
1120 &Handles
1121 );
1122 if (EFI_ERROR (Status)) {
1123 Handles = NULL;
1124 HandleCount = 0;
1125 }
1126
1127 Handle = NULL;
1128 for (Index = 0; Index < HandleCount; Index++) {
1129 Node = DevicePathFromHandle (Handles[Index]);
1130 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1131 if (!EFI_ERROR (Status) &&
1132 (Handle == LoadFileHandle) &&
1133 (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)) {
1134 Handle = Handles[Index];
1135 break;
1136 }
1137 }
1138
1139 if (Handles != NULL) {
1140 FreePool (Handles);
1141 }
1142
1143 if (Index != HandleCount) {
1144 return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), FullPath, FileSize);
1145 } else {
1146 return NULL;
1147 }
1148 }
1149
1150
1151 /**
1152 Get the file buffer from the specified Load File instance.
1153
1154 @param LoadFileHandle The specified Load File instance.
1155 @param FilePath The file path which will pass to LoadFile().
1156 @param FullPath Return the full device path pointing to the load option.
1157 @param FileSize Return the size of the load option.
1158
1159 @return The load option buffer or NULL if fails.
1160 **/
1161 VOID *
1162 BmGetFileBufferFromLoadFile (
1163 EFI_HANDLE LoadFileHandle,
1164 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1165 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1166 OUT UINTN *FileSize
1167 )
1168 {
1169 EFI_STATUS Status;
1170 EFI_LOAD_FILE_PROTOCOL *LoadFile;
1171 VOID *FileBuffer;
1172 BOOLEAN LoadFileSystem;
1173 UINTN BufferSize;
1174
1175 *FileSize = 0;
1176
1177 Status = gBS->OpenProtocol (
1178 LoadFileHandle,
1179 &gEfiLoadFileProtocolGuid,
1180 (VOID **) &LoadFile,
1181 gImageHandle,
1182 NULL,
1183 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1184 );
1185 ASSERT_EFI_ERROR (Status);
1186
1187 FileBuffer = NULL;
1188 BufferSize = 0;
1189 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1190 if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
1191 return NULL;
1192 }
1193
1194 LoadFileSystem = (BOOLEAN) (Status == EFI_WARN_FILE_SYSTEM);
1195 FileBuffer = LoadFileSystem ? AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize)) : AllocatePool (BufferSize);
1196 if (FileBuffer == NULL) {
1197 return NULL;
1198 }
1199
1200 Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
1201 if (EFI_ERROR (Status)) {
1202 if (LoadFileSystem) {
1203 FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
1204 } else {
1205 FreePool (FileBuffer);
1206 }
1207 return NULL;
1208 }
1209
1210 if (LoadFileSystem) {
1211 FileBuffer = BmGetFileBufferFromLoadFileSystem (LoadFileHandle, FullPath, FileSize);
1212 } else {
1213 *FileSize = BufferSize;
1214 *FullPath = DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
1215 }
1216
1217 return FileBuffer;
1218 }
1219
1220 /**
1221 Get the file buffer from all the Load File instances.
1222
1223 @param FilePath The media device path pointing to a LoadFile instance.
1224 @param FullPath Return the full device path pointing to the load option.
1225 @param FileSize Return the size of the load option.
1226
1227 @return The load option buffer.
1228 **/
1229 VOID *
1230 BmGetFileBufferFromLoadFiles (
1231 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1232 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1233 OUT UINTN *FileSize
1234 )
1235 {
1236 EFI_STATUS Status;
1237 EFI_HANDLE Handle;
1238 EFI_HANDLE *Handles;
1239 UINTN HandleCount;
1240 UINTN Index;
1241 EFI_DEVICE_PATH_PROTOCOL *Node;
1242
1243 //
1244 // Get file buffer from load file instance.
1245 //
1246 Node = FilePath;
1247 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
1248 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1249 //
1250 // When wide match happens, pass full device path to LoadFile (),
1251 // otherwise, pass remaining device path to LoadFile ().
1252 //
1253 FilePath = Node;
1254 } else {
1255 Handle = NULL;
1256 //
1257 // Use wide match algorithm to find one when
1258 // cannot find a LoadFile instance to exactly match the FilePath
1259 //
1260 Status = gBS->LocateHandleBuffer (
1261 ByProtocol,
1262 &gEfiLoadFileProtocolGuid,
1263 NULL,
1264 &HandleCount,
1265 &Handles
1266 );
1267 if (EFI_ERROR (Status)) {
1268 Handles = NULL;
1269 HandleCount = 0;
1270 }
1271 for (Index = 0; Index < HandleCount; Index++) {
1272 if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
1273 Handle = Handles[Index];
1274 break;
1275 }
1276 }
1277 if (Handles != NULL) {
1278 FreePool (Handles);
1279 }
1280 }
1281
1282 if (Handle == NULL) {
1283 return NULL;
1284 }
1285
1286 return BmGetFileBufferFromLoadFile (Handle, FilePath, FullPath, FileSize);
1287 }
1288
1289 /**
1290 Get the load option by its device path.
1291
1292 @param FilePath The device path pointing to a load option.
1293 It could be a short-form device path.
1294 @param FullPath Return the full device path of the load option after
1295 short-form device path expanding.
1296 Caller is responsible to free it.
1297 @param FileSize Return the load option size.
1298
1299 @return The load option buffer. Caller is responsible to free the memory.
1300 **/
1301 VOID *
1302 BmGetLoadOptionBuffer (
1303 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1304 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1305 OUT UINTN *FileSize
1306 )
1307 {
1308 EFI_HANDLE Handle;
1309 VOID *FileBuffer;
1310 UINT32 AuthenticationStatus;
1311 EFI_DEVICE_PATH_PROTOCOL *Node;
1312 EFI_STATUS Status;
1313
1314 ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
1315
1316 EfiBootManagerConnectDevicePath (FilePath, NULL);
1317
1318 *FullPath = NULL;
1319 *FileSize = 0;
1320 FileBuffer = NULL;
1321
1322 //
1323 // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
1324 //
1325 Node = FilePath;
1326 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1327 if (EFI_ERROR (Status)) {
1328 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
1329 }
1330
1331 if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
1332 return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
1333 }
1334
1335 //
1336 // Expand the short-form device path to full device path
1337 //
1338 if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1339 (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
1340 //
1341 // Expand the Harddrive device path
1342 //
1343 return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
1344 } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
1345 (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP)) {
1346 //
1347 // Expand the File-path device path
1348 //
1349 return BmExpandFileDevicePath (FilePath, FullPath, FileSize);
1350 } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
1351 (DevicePathSubType (FilePath) == MSG_URI_DP)) {
1352 //
1353 // Expand the URI device path
1354 //
1355 return BmExpandUriDevicePath (FilePath, FullPath, FileSize);
1356 } else {
1357 for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
1358 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
1359 ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
1360 break;
1361 }
1362 }
1363
1364 if (!IsDevicePathEnd (Node)) {
1365 //
1366 // Expand the USB WWID/Class device path
1367 //
1368 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1369 if ((FileBuffer == NULL) && (FilePath == Node)) {
1370 //
1371 // Boot Option device path starts with USB Class or USB WWID device path.
1372 // For Boot Option device path which doesn't begin with the USB Class or
1373 // USB WWID device path, it's not needed to connect again here.
1374 //
1375 BmConnectUsbShortFormDevicePath (FilePath);
1376 FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
1377 }
1378 return FileBuffer;
1379 }
1380 }
1381
1382 //
1383 // Get file buffer from FV file path.
1384 //
1385 if (BmIsFvFilePath (FilePath)) {
1386 return BmGetFileBufferByFvFilePath (FilePath, FullPath, FileSize);
1387 }
1388
1389 //
1390 // Get file buffer from simple file system.
1391 //
1392 Node = FilePath;
1393 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
1394 if (!EFI_ERROR (Status)) {
1395 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
1396 if (FileBuffer != NULL) {
1397 *FullPath = DuplicateDevicePath (FilePath);
1398 }
1399 return FileBuffer;
1400 }
1401
1402 return BmGetFileBufferFromLoadFiles (FilePath, FullPath, FileSize);
1403 }
1404
1405 /**
1406 Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
1407 also signals the EFI ready to boot event. If the device path for the option
1408 starts with a BBS device path a legacy boot is attempted via the registered
1409 gLegacyBoot function. Short form device paths are also supported via this
1410 rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
1411 MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
1412 If the BootOption Device Path fails the removable media boot algorithm
1413 is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
1414 is tried per processor type)
1415
1416 @param BootOption Boot Option to try and boot.
1417 On return, BootOption->Status contains the boot status.
1418 EFI_SUCCESS BootOption was booted
1419 EFI_UNSUPPORTED A BBS device path was found with no valid callback
1420 registered via EfiBootManagerInitialize().
1421 EFI_NOT_FOUND The BootOption was not found on the system
1422 !EFI_SUCCESS BootOption failed with this error status
1423
1424 **/
1425 VOID
1426 EFIAPI
1427 EfiBootManagerBoot (
1428 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1429 )
1430 {
1431 EFI_STATUS Status;
1432 EFI_HANDLE ImageHandle;
1433 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1434 UINT16 Uint16;
1435 UINTN OptionNumber;
1436 UINTN OriginalOptionNumber;
1437 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1438 EFI_DEVICE_PATH_PROTOCOL *Node;
1439 EFI_HANDLE FvHandle;
1440 VOID *FileBuffer;
1441 UINTN FileSize;
1442 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
1443 EFI_EVENT LegacyBootEvent;
1444
1445 if (BootOption == NULL) {
1446 return;
1447 }
1448
1449 if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
1450 BootOption->Status = EFI_INVALID_PARAMETER;
1451 return;
1452 }
1453
1454 //
1455 // 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")
1456 //
1457 OptionNumber = BmFindBootOptionInVariable (BootOption);
1458 if (OptionNumber == LoadOptionNumberUnassigned) {
1459 Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
1460 if (!EFI_ERROR (Status)) {
1461 //
1462 // Save the BootOption->OptionNumber to restore later
1463 //
1464 OptionNumber = Uint16;
1465 OriginalOptionNumber = BootOption->OptionNumber;
1466 BootOption->OptionNumber = OptionNumber;
1467 Status = EfiBootManagerLoadOptionToVariable (BootOption);
1468 BootOption->OptionNumber = OriginalOptionNumber;
1469 }
1470
1471 if (EFI_ERROR (Status)) {
1472 DEBUG ((EFI_D_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
1473 BootOption->Status = Status;
1474 return ;
1475 }
1476 }
1477
1478 //
1479 // 2. Set BootCurrent
1480 //
1481 Uint16 = (UINT16) OptionNumber;
1482 BmSetVariableAndReportStatusCodeOnError (
1483 L"BootCurrent",
1484 &gEfiGlobalVariableGuid,
1485 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
1486 sizeof (UINT16),
1487 &Uint16
1488 );
1489
1490 //
1491 // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
1492 // the boot option.
1493 //
1494 Node = BootOption->FilePath;
1495 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
1496 if (!EFI_ERROR (Status) && CompareGuid (
1497 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
1498 PcdGetPtr (PcdBootManagerMenuFile)
1499 )) {
1500 DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
1501 BmStopHotkeyService (NULL, NULL);
1502 } else {
1503 EfiSignalEventReadyToBoot();
1504 //
1505 // Report Status Code to indicate ReadyToBoot was signalled
1506 //
1507 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
1508 //
1509 // 4. Repair system through DriverHealth protocol
1510 //
1511 BmRepairAllControllers ();
1512 }
1513
1514 PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1515
1516 //
1517 // 5. Load EFI boot option to ImageHandle
1518 //
1519 ImageHandle = NULL;
1520 if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
1521 Status = EFI_NOT_FOUND;
1522 FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
1523 DEBUG_CODE (
1524 if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
1525 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
1526 BmPrintDp (BootOption->FilePath);
1527 DEBUG ((EFI_D_INFO, " -> "));
1528 BmPrintDp (FilePath);
1529 DEBUG ((EFI_D_INFO, "\n"));
1530 }
1531 );
1532 if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
1533 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
1534 Status = gBS->LoadImage (
1535 TRUE,
1536 gImageHandle,
1537 FilePath,
1538 FileBuffer,
1539 FileSize,
1540 &ImageHandle
1541 );
1542 }
1543 if (FileBuffer != NULL) {
1544 FreePool (FileBuffer);
1545 }
1546 if (FilePath != NULL) {
1547 FreePool (FilePath);
1548 }
1549
1550 if (EFI_ERROR (Status)) {
1551 //
1552 // Report Status Code to indicate that the failure to load boot option
1553 //
1554 REPORT_STATUS_CODE (
1555 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1556 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
1557 );
1558 BootOption->Status = Status;
1559 return;
1560 }
1561 }
1562
1563 //
1564 // 6. Adjust the different type memory page number just before booting
1565 // and save the updated info into the variable for next boot to use
1566 //
1567 BmSetMemoryTypeInformationVariable (
1568 (BOOLEAN) ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
1569 );
1570
1571 DEBUG_CODE_BEGIN();
1572 if (BootOption->Description == NULL) {
1573 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
1574 } else {
1575 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
1576 }
1577 DEBUG_CODE_END();
1578
1579 //
1580 // Check to see if we should legacy BOOT. If yes then do the legacy boot
1581 // Write boot to OS performance data for Legacy boot
1582 //
1583 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
1584 if (mBmLegacyBoot != NULL) {
1585 //
1586 // Write boot to OS performance data for legacy boot.
1587 //
1588 PERF_CODE (
1589 //
1590 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1591 //
1592 Status = EfiCreateEventLegacyBootEx(
1593 TPL_NOTIFY,
1594 BmWriteBootToOsPerformanceData,
1595 NULL,
1596 &LegacyBootEvent
1597 );
1598 ASSERT_EFI_ERROR (Status);
1599 );
1600
1601 mBmLegacyBoot (BootOption);
1602 } else {
1603 BootOption->Status = EFI_UNSUPPORTED;
1604 }
1605
1606 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1607 return;
1608 }
1609
1610 //
1611 // Provide the image with its load options
1612 //
1613 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1614 ASSERT_EFI_ERROR (Status);
1615
1616 if (!BmIsAutoCreateBootOption (BootOption)) {
1617 ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
1618 ImageInfo->LoadOptions = BootOption->OptionalData;
1619 }
1620
1621 //
1622 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
1623 //
1624 ImageInfo->ParentHandle = NULL;
1625
1626 //
1627 // Before calling the image, enable the Watchdog Timer for 5 minutes period
1628 //
1629 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
1630
1631 //
1632 // Write boot to OS performance data for UEFI boot
1633 //
1634 PERF_CODE (
1635 BmWriteBootToOsPerformanceData (NULL, NULL);
1636 );
1637
1638 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
1639
1640 Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
1641 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
1642 BootOption->Status = Status;
1643 if (EFI_ERROR (Status)) {
1644 //
1645 // Report Status Code to indicate that boot failure
1646 //
1647 REPORT_STATUS_CODE (
1648 EFI_ERROR_CODE | EFI_ERROR_MINOR,
1649 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
1650 );
1651 }
1652 PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32) OptionNumber);
1653
1654 //
1655 // Clear the Watchdog Timer after the image returns
1656 //
1657 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
1658
1659 //
1660 // Set Logo status invalid after trying one boot option
1661 //
1662 BootLogo = NULL;
1663 Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
1664 if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
1665 Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
1666 ASSERT_EFI_ERROR (Status);
1667 }
1668
1669 //
1670 // Clear Boot Current
1671 //
1672 Status = gRT->SetVariable (
1673 L"BootCurrent",
1674 &gEfiGlobalVariableGuid,
1675 0,
1676 0,
1677 NULL
1678 );
1679 //
1680 // Deleting variable with current variable implementation shouldn't fail.
1681 // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
1682 // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
1683 //
1684 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
1685 }
1686
1687 /**
1688 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
1689 instances, has the same partition node with HardDriveDevicePath device path
1690
1691 @param BlockIoDevicePath Multi device path instances which need to check
1692 @param HardDriveDevicePath A device path which starts with a hard drive media
1693 device path.
1694
1695 @retval TRUE There is a matched device path instance.
1696 @retval FALSE There is no matched device path instance.
1697
1698 **/
1699 BOOLEAN
1700 BmMatchPartitionDevicePathNode (
1701 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
1702 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
1703 )
1704 {
1705 HARDDRIVE_DEVICE_PATH *Node;
1706
1707 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
1708 return FALSE;
1709 }
1710
1711 //
1712 // find the partition device path node
1713 //
1714 while (!IsDevicePathEnd (BlockIoDevicePath)) {
1715 if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
1716 (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
1717 ) {
1718 break;
1719 }
1720
1721 BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
1722 }
1723
1724 if (IsDevicePathEnd (BlockIoDevicePath)) {
1725 return FALSE;
1726 }
1727
1728 //
1729 // See if the harddrive device path in blockio matches the orig Hard Drive Node
1730 //
1731 Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
1732
1733 //
1734 // Match Signature and PartitionNumber.
1735 // Unused bytes in Signature are initiaized with zeros.
1736 //
1737 return (BOOLEAN) (
1738 (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
1739 (Node->MBRType == HardDriveDevicePath->MBRType) &&
1740 (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
1741 (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
1742 );
1743 }
1744
1745 /**
1746 Emuerate all possible bootable medias in the following order:
1747 1. Removable BlockIo - The boot option only points to the removable media
1748 device, like USB key, DVD, Floppy etc.
1749 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
1750 like HardDisk.
1751 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
1752 SimpleFileSystem Protocol, but not supporting BlockIo
1753 protocol.
1754 4. LoadFile - The boot option points to the media supporting
1755 LoadFile protocol.
1756 Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
1757
1758 @param BootOptionCount Return the boot option count which has been found.
1759
1760 @retval Pointer to the boot option array.
1761 **/
1762 EFI_BOOT_MANAGER_LOAD_OPTION *
1763 BmEnumerateBootOptions (
1764 UINTN *BootOptionCount
1765 )
1766 {
1767 EFI_STATUS Status;
1768 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1769 UINTN HandleCount;
1770 EFI_HANDLE *Handles;
1771 EFI_BLOCK_IO_PROTOCOL *BlkIo;
1772 UINTN Removable;
1773 UINTN Index;
1774 CHAR16 *Description;
1775
1776 ASSERT (BootOptionCount != NULL);
1777
1778 *BootOptionCount = 0;
1779 BootOptions = NULL;
1780
1781 //
1782 // Parse removable block io followed by fixed block io
1783 //
1784 gBS->LocateHandleBuffer (
1785 ByProtocol,
1786 &gEfiBlockIoProtocolGuid,
1787 NULL,
1788 &HandleCount,
1789 &Handles
1790 );
1791
1792 for (Removable = 0; Removable < 2; Removable++) {
1793 for (Index = 0; Index < HandleCount; Index++) {
1794 Status = gBS->HandleProtocol (
1795 Handles[Index],
1796 &gEfiBlockIoProtocolGuid,
1797 (VOID **) &BlkIo
1798 );
1799 if (EFI_ERROR (Status)) {
1800 continue;
1801 }
1802
1803 //
1804 // Skip the logical partitions
1805 //
1806 if (BlkIo->Media->LogicalPartition) {
1807 continue;
1808 }
1809
1810 //
1811 // Skip the fixed block io then the removable block io
1812 //
1813 if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
1814 continue;
1815 }
1816
1817 Description = BmGetBootDescription (Handles[Index]);
1818 BootOptions = ReallocatePool (
1819 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1820 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1821 BootOptions
1822 );
1823 ASSERT (BootOptions != NULL);
1824
1825 Status = EfiBootManagerInitializeLoadOption (
1826 &BootOptions[(*BootOptionCount)++],
1827 LoadOptionNumberUnassigned,
1828 LoadOptionTypeBoot,
1829 LOAD_OPTION_ACTIVE,
1830 Description,
1831 DevicePathFromHandle (Handles[Index]),
1832 NULL,
1833 0
1834 );
1835 ASSERT_EFI_ERROR (Status);
1836
1837 FreePool (Description);
1838 }
1839 }
1840
1841 if (HandleCount != 0) {
1842 FreePool (Handles);
1843 }
1844
1845 //
1846 // Parse simple file system not based on block io
1847 //
1848 gBS->LocateHandleBuffer (
1849 ByProtocol,
1850 &gEfiSimpleFileSystemProtocolGuid,
1851 NULL,
1852 &HandleCount,
1853 &Handles
1854 );
1855 for (Index = 0; Index < HandleCount; Index++) {
1856 Status = gBS->HandleProtocol (
1857 Handles[Index],
1858 &gEfiBlockIoProtocolGuid,
1859 (VOID **) &BlkIo
1860 );
1861 if (!EFI_ERROR (Status)) {
1862 //
1863 // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
1864 //
1865 continue;
1866 }
1867 Description = BmGetBootDescription (Handles[Index]);
1868 BootOptions = ReallocatePool (
1869 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1870 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1871 BootOptions
1872 );
1873 ASSERT (BootOptions != NULL);
1874
1875 Status = EfiBootManagerInitializeLoadOption (
1876 &BootOptions[(*BootOptionCount)++],
1877 LoadOptionNumberUnassigned,
1878 LoadOptionTypeBoot,
1879 LOAD_OPTION_ACTIVE,
1880 Description,
1881 DevicePathFromHandle (Handles[Index]),
1882 NULL,
1883 0
1884 );
1885 ASSERT_EFI_ERROR (Status);
1886 FreePool (Description);
1887 }
1888
1889 if (HandleCount != 0) {
1890 FreePool (Handles);
1891 }
1892
1893 //
1894 // Parse load file, assuming UEFI Network boot option
1895 //
1896 gBS->LocateHandleBuffer (
1897 ByProtocol,
1898 &gEfiLoadFileProtocolGuid,
1899 NULL,
1900 &HandleCount,
1901 &Handles
1902 );
1903 for (Index = 0; Index < HandleCount; Index++) {
1904
1905 Description = BmGetBootDescription (Handles[Index]);
1906 BootOptions = ReallocatePool (
1907 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1908 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1909 BootOptions
1910 );
1911 ASSERT (BootOptions != NULL);
1912
1913 Status = EfiBootManagerInitializeLoadOption (
1914 &BootOptions[(*BootOptionCount)++],
1915 LoadOptionNumberUnassigned,
1916 LoadOptionTypeBoot,
1917 LOAD_OPTION_ACTIVE,
1918 Description,
1919 DevicePathFromHandle (Handles[Index]),
1920 NULL,
1921 0
1922 );
1923 ASSERT_EFI_ERROR (Status);
1924 FreePool (Description);
1925 }
1926
1927 if (HandleCount != 0) {
1928 FreePool (Handles);
1929 }
1930
1931 BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
1932 return BootOptions;
1933 }
1934
1935 /**
1936 The function enumerates all boot options, creates them and registers them in the BootOrder variable.
1937 **/
1938 VOID
1939 EFIAPI
1940 EfiBootManagerRefreshAllBootOption (
1941 VOID
1942 )
1943 {
1944 EFI_STATUS Status;
1945 EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
1946 UINTN NvBootOptionCount;
1947 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1948 UINTN BootOptionCount;
1949 UINTN Index;
1950
1951 //
1952 // Optionally refresh the legacy boot option
1953 //
1954 if (mBmRefreshLegacyBootOption != NULL) {
1955 mBmRefreshLegacyBootOption ();
1956 }
1957
1958 BootOptions = BmEnumerateBootOptions (&BootOptionCount);
1959 NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
1960
1961 //
1962 // Mark the boot option as added by BDS by setting OptionalData to a special GUID
1963 //
1964 for (Index = 0; Index < BootOptionCount; Index++) {
1965 BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
1966 BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
1967 }
1968
1969 //
1970 // Remove invalid EFI boot options from NV
1971 //
1972 for (Index = 0; Index < NvBootOptionCount; Index++) {
1973 if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
1974 (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
1975 ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
1976 ) {
1977 //
1978 // Only check those added by BDS
1979 // so that the boot options added by end-user or OS installer won't be deleted
1980 //
1981 if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == (UINTN) -1) {
1982 Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
1983 //
1984 // Deleting variable with current variable implementation shouldn't fail.
1985 //
1986 ASSERT_EFI_ERROR (Status);
1987 }
1988 }
1989 }
1990
1991 //
1992 // Add new EFI boot options to NV
1993 //
1994 for (Index = 0; Index < BootOptionCount; Index++) {
1995 if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == (UINTN) -1) {
1996 EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
1997 //
1998 // Try best to add the boot options so continue upon failure.
1999 //
2000 }
2001 }
2002
2003 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2004 EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
2005 }
2006
2007 /**
2008 This function is called to create the boot option for the Boot Manager Menu.
2009
2010 The Boot Manager Menu is shown after successfully booting a boot option.
2011 Assume the BootManagerMenuFile is in the same FV as the module links to this library.
2012
2013 @param BootOption Return the boot option of the Boot Manager Menu
2014
2015 @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
2016 @retval Status Return status of gRT->SetVariable (). BootOption still points
2017 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2018 **/
2019 EFI_STATUS
2020 BmRegisterBootManagerMenu (
2021 OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2022 )
2023 {
2024 EFI_STATUS Status;
2025 CHAR16 *Description;
2026 UINTN DescriptionLength;
2027 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2028 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
2029 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
2030
2031 Status = GetSectionFromFv (
2032 PcdGetPtr (PcdBootManagerMenuFile),
2033 EFI_SECTION_USER_INTERFACE,
2034 0,
2035 (VOID **) &Description,
2036 &DescriptionLength
2037 );
2038 if (EFI_ERROR (Status)) {
2039 Description = NULL;
2040 }
2041
2042 EfiInitializeFwVolDevicepathNode (&FileNode, PcdGetPtr (PcdBootManagerMenuFile));
2043 Status = gBS->HandleProtocol (
2044 gImageHandle,
2045 &gEfiLoadedImageProtocolGuid,
2046 (VOID **) &LoadedImage
2047 );
2048 ASSERT_EFI_ERROR (Status);
2049 DevicePath = AppendDevicePathNode (
2050 DevicePathFromHandle (LoadedImage->DeviceHandle),
2051 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
2052 );
2053 ASSERT (DevicePath != NULL);
2054
2055 Status = EfiBootManagerInitializeLoadOption (
2056 BootOption,
2057 LoadOptionNumberUnassigned,
2058 LoadOptionTypeBoot,
2059 LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
2060 (Description != NULL) ? Description : L"Boot Manager Menu",
2061 DevicePath,
2062 NULL,
2063 0
2064 );
2065 ASSERT_EFI_ERROR (Status);
2066 FreePool (DevicePath);
2067 if (Description != NULL) {
2068 FreePool (Description);
2069 }
2070
2071 DEBUG_CODE (
2072 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2073 UINTN BootOptionCount;
2074
2075 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2076 ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
2077 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2078 );
2079
2080 return EfiBootManagerAddLoadOptionVariable (BootOption, 0);
2081 }
2082
2083 /**
2084 Return the boot option corresponding to the Boot Manager Menu.
2085 It may automatically create one if the boot option hasn't been created yet.
2086
2087 @param BootOption Return the Boot Manager Menu.
2088
2089 @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
2090 @retval Status Return status of gRT->SetVariable (). BootOption still points
2091 to the Boot Manager Menu even the Status is not EFI_SUCCESS.
2092 **/
2093 EFI_STATUS
2094 EFIAPI
2095 EfiBootManagerGetBootManagerMenu (
2096 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
2097 )
2098 {
2099 EFI_STATUS Status;
2100 UINTN BootOptionCount;
2101 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
2102 UINTN Index;
2103 EFI_DEVICE_PATH_PROTOCOL *Node;
2104 EFI_HANDLE FvHandle;
2105
2106 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
2107
2108 for (Index = 0; Index < BootOptionCount; Index++) {
2109 Node = BootOptions[Index].FilePath;
2110 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
2111 if (!EFI_ERROR (Status)) {
2112 if (CompareGuid (
2113 EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
2114 PcdGetPtr (PcdBootManagerMenuFile)
2115 )
2116 ) {
2117 Status = EfiBootManagerInitializeLoadOption (
2118 BootOption,
2119 BootOptions[Index].OptionNumber,
2120 BootOptions[Index].OptionType,
2121 BootOptions[Index].Attributes,
2122 BootOptions[Index].Description,
2123 BootOptions[Index].FilePath,
2124 BootOptions[Index].OptionalData,
2125 BootOptions[Index].OptionalDataSize
2126 );
2127 ASSERT_EFI_ERROR (Status);
2128 break;
2129 }
2130 }
2131 }
2132
2133 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
2134
2135 //
2136 // Automatically create the Boot#### for Boot Manager Menu when not found.
2137 //
2138 if (Index == BootOptionCount) {
2139 return BmRegisterBootManagerMenu (BootOption);
2140 } else {
2141 return EFI_SUCCESS;
2142 }
2143 }
2144