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