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