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