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