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