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