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