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