VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c@ 89977

最後變更 在這個檔案從89977是 85718,由 vboxsync 提交於 5 年 前

Devices/EFI: Merge edk-stable202005 and make it build, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 45.4 KB
 
1/** @file
2 Load option library functions which relate with creating and processing load options.
3
4Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
5(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
6SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "InternalBm.h"
11
12GLOBAL_REMOVE_IF_UNREFERENCED
13 CHAR16 *mBmLoadOptionName[] = {
14 L"Driver",
15 L"SysPrep",
16 L"Boot",
17 L"PlatformRecovery"
18 };
19
20GLOBAL_REMOVE_IF_UNREFERENCED
21 CHAR16 *mBmLoadOptionOrderName[] = {
22 EFI_DRIVER_ORDER_VARIABLE_NAME,
23 EFI_SYS_PREP_ORDER_VARIABLE_NAME,
24 EFI_BOOT_ORDER_VARIABLE_NAME,
25 NULL // PlatformRecovery#### doesn't have associated *Order variable
26 };
27
28/**
29 Call Visitor function for each variable in variable storage.
30
31 @param Visitor Visitor function.
32 @param Context The context passed to Visitor function.
33**/
34VOID
35BmForEachVariable (
36 BM_VARIABLE_VISITOR Visitor,
37 VOID *Context
38 )
39{
40 EFI_STATUS Status;
41 CHAR16 *Name;
42 EFI_GUID Guid;
43 UINTN NameSize;
44 UINTN NewNameSize;
45
46 NameSize = sizeof (CHAR16);
47 Name = AllocateZeroPool (NameSize);
48 ASSERT (Name != NULL);
49 while (TRUE) {
50 NewNameSize = NameSize;
51 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
52 if (Status == EFI_BUFFER_TOO_SMALL) {
53 Name = ReallocatePool (NameSize, NewNameSize, Name);
54 ASSERT (Name != NULL);
55 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
56 NameSize = NewNameSize;
57 }
58
59 if (Status == EFI_NOT_FOUND) {
60 break;
61 }
62 ASSERT_EFI_ERROR (Status);
63
64 Visitor (Name, &Guid, Context);
65 }
66
67 FreePool (Name);
68}
69
70/**
71 Get the Option Number that wasn't used.
72
73 @param LoadOptionType The load option type.
74 @param FreeOptionNumber Return the minimal free option number.
75
76 @retval EFI_SUCCESS The option number is found and will be returned.
77 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
78 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
79
80**/
81EFI_STATUS
82BmGetFreeOptionNumber (
83 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
84 OUT UINT16 *FreeOptionNumber
85 )
86{
87
88 UINTN OptionNumber;
89 UINTN Index;
90 UINT16 *OptionOrder;
91 UINTN OptionOrderSize;
92 UINT16 *BootNext;
93
94 ASSERT (FreeOptionNumber != NULL);
95 ASSERT (LoadOptionType == LoadOptionTypeDriver ||
96 LoadOptionType == LoadOptionTypeBoot ||
97 LoadOptionType == LoadOptionTypeSysPrep);
98
99 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
100 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
101
102 BootNext = NULL;
103 if (LoadOptionType == LoadOptionTypeBoot) {
104 GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
105 }
106
107 for (OptionNumber = 0;
108 OptionNumber < OptionOrderSize / sizeof (UINT16)
109 + ((BootNext != NULL) ? 1 : 0);
110 OptionNumber++
111 ) {
112 //
113 // Search in OptionOrder whether the OptionNumber exists
114 //
115 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
116 if (OptionNumber == OptionOrder[Index]) {
117 break;
118 }
119 }
120
121 //
122 // We didn't find it in the ****Order array and it doesn't equal to BootNext
123 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
124 //
125 if ((Index == OptionOrderSize / sizeof (UINT16)) &&
126 ((BootNext == NULL) || (OptionNumber != *BootNext))
127 ) {
128 break;
129 }
130 }
131 if (OptionOrder != NULL) {
132 FreePool (OptionOrder);
133 }
134
135 if (BootNext != NULL) {
136 FreePool (BootNext);
137 }
138
139 //
140 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
141 // OptionNumber equals to 0x10000 which is not valid.
142 //
143 ASSERT (OptionNumber <= 0x10000);
144 if (OptionNumber == 0x10000) {
145 return EFI_OUT_OF_RESOURCES;
146 } else {
147 *FreeOptionNumber = (UINT16) OptionNumber;
148 return EFI_SUCCESS;
149 }
150}
151
152/**
153 Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable
154 from the load option.
155
156 @param LoadOption Pointer to the load option.
157
158 @retval EFI_SUCCESS The variable was created.
159 @retval Others Error status returned by RT->SetVariable.
160**/
161EFI_STATUS
162EFIAPI
163EfiBootManagerLoadOptionToVariable (
164 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option
165 )
166{
167 EFI_STATUS Status;
168 UINTN VariableSize;
169 UINT8 *Variable;
170 UINT8 *Ptr;
171 CHAR16 OptionName[BM_OPTION_NAME_LEN];
172 CHAR16 *Description;
173 CHAR16 NullChar;
174 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
175 UINT32 VariableAttributes;
176
177 if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
178 (Option->FilePath == NULL) ||
179 ((UINT32) Option->OptionType >= LoadOptionTypeMax)
180 ) {
181 return EFI_INVALID_PARAMETER;
182 }
183
184 //
185 // Convert NULL description to empty description
186 //
187 NullChar = L'\0';
188 Description = Option->Description;
189 if (Description == NULL) {
190 Description = &NullChar;
191 }
192
193 /*
194 UINT32 Attributes;
195 UINT16 FilePathListLength;
196 CHAR16 Description[];
197 EFI_DEVICE_PATH_PROTOCOL FilePathList[];
198 UINT8 OptionalData[];
199TODO: FilePathList[] IS:
200A packed array of UEFI device paths. The first element of the
201array is a device path that describes the device and location of the
202Image for this load option. The FilePathList[0] is specific
203to the device type. Other device paths may optionally exist in the
204FilePathList, but their usage is OSV specific. Each element
205in the array is variable length, and ends at the device path end
206structure.
207 */
208 VariableSize = sizeof (Option->Attributes)
209 + sizeof (UINT16)
210 + StrSize (Description)
211 + GetDevicePathSize (Option->FilePath)
212 + Option->OptionalDataSize;
213
214 Variable = AllocatePool (VariableSize);
215 ASSERT (Variable != NULL);
216
217 Ptr = Variable;
218 WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
219 Ptr += sizeof (Option->Attributes);
220
221 WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
222 Ptr += sizeof (UINT16);
223
224 CopyMem (Ptr, Description, StrSize (Description));
225 Ptr += StrSize (Description);
226
227 CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
228 Ptr += GetDevicePathSize (Option->FilePath);
229
230 CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
231
232 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
233
234 VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
235 if (Option->OptionType == LoadOptionTypePlatformRecovery) {
236 //
237 // Lock the PlatformRecovery####
238 //
239 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
240 if (!EFI_ERROR (Status)) {
241 Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);
242 ASSERT_EFI_ERROR (Status);
243 }
244 VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
245 }
246
247 Status = gRT->SetVariable (
248 OptionName,
249 &gEfiGlobalVariableGuid,
250 VariableAttributes,
251 VariableSize,
252 Variable
253 );
254 FreePool (Variable);
255
256 return Status;
257}
258
259/**
260 Update order variable .
261
262 @param OptionOrderName Order variable name which need to be updated.
263 @param OptionNumber Option number for the new option.
264 @param Position Position of the new load option to put in the ****Order variable.
265
266 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
267 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
268 @retval EFI_STATUS Return the status of gRT->SetVariable ().
269
270**/
271EFI_STATUS
272BmAddOptionNumberToOrderVariable (
273 IN CHAR16 *OptionOrderName,
274 IN UINT16 OptionNumber,
275 IN UINTN Position
276 )
277{
278 EFI_STATUS Status;
279 UINTN Index;
280 UINT16 *OptionOrder;
281 UINT16 *NewOptionOrder;
282 UINTN OptionOrderSize;
283 //
284 // Update the option order variable
285 //
286 GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
287 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
288
289 Status = EFI_SUCCESS;
290 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
291 if (OptionOrder[Index] == OptionNumber) {
292 Status = EFI_ALREADY_STARTED;
293 break;
294 }
295 }
296
297 if (!EFI_ERROR (Status)) {
298 Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
299
300 NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
301 ASSERT (NewOptionOrder != NULL);
302 if (OptionOrderSize != 0) {
303 CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
304 CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
305 }
306 NewOptionOrder[Position] = OptionNumber;
307
308 Status = gRT->SetVariable (
309 OptionOrderName,
310 &gEfiGlobalVariableGuid,
311 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
312 OptionOrderSize + sizeof (UINT16),
313 NewOptionOrder
314 );
315 FreePool (NewOptionOrder);
316 }
317
318 if (OptionOrder != NULL) {
319 FreePool (OptionOrder);
320 }
321
322 return Status;
323}
324
325/**
326 This function will register the new Boot####, Driver#### or SysPrep#### option.
327 After the *#### is updated, the *Order will also be updated.
328
329 @param Option Pointer to load option to add. If on input
330 Option->OptionNumber is LoadOptionNumberUnassigned,
331 then on output Option->OptionNumber is updated to
332 the number of the new Boot####,
333 Driver#### or SysPrep#### option.
334 @param Position Position of the new load option to put in the ****Order variable.
335
336 @retval EFI_SUCCESS The *#### have been successfully registered.
337 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
338 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
339 Note: this API only adds new load option, no replacement support.
340 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
341 option number specified in the Option is LoadOptionNumberUnassigned.
342 @return Status codes of gRT->SetVariable ().
343
344**/
345EFI_STATUS
346EFIAPI
347EfiBootManagerAddLoadOptionVariable (
348 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
349 IN UINTN Position
350 )
351{
352 EFI_STATUS Status;
353 UINT16 OptionNumber;
354
355 if (Option == NULL) {
356 return EFI_INVALID_PARAMETER;
357 }
358
359 if (Option->OptionType != LoadOptionTypeDriver &&
360 Option->OptionType != LoadOptionTypeSysPrep &&
361 Option->OptionType != LoadOptionTypeBoot
362 ) {
363 return EFI_INVALID_PARAMETER;
364 }
365
366 //
367 // Get the free option number if the option number is unassigned
368 //
369 if (Option->OptionNumber == LoadOptionNumberUnassigned) {
370 Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
371 if (EFI_ERROR (Status)) {
372 return Status;
373 }
374 Option->OptionNumber = OptionNumber;
375 }
376
377 if (Option->OptionNumber >= LoadOptionNumberMax) {
378 return EFI_INVALID_PARAMETER;
379 }
380
381 Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
382 if (!EFI_ERROR (Status)) {
383 //
384 // Save the Boot#### or Driver#### variable
385 //
386 Status = EfiBootManagerLoadOptionToVariable (Option);
387 if (EFI_ERROR (Status)) {
388 //
389 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
390 //
391 EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
392 }
393 }
394
395 return Status;
396}
397
398/**
399 Sort the load option. The DriverOrder or BootOrder will be re-created to
400 reflect the new order.
401
402 @param OptionType Load option type
403 @param CompareFunction The comparator
404**/
405VOID
406EFIAPI
407EfiBootManagerSortLoadOptionVariable (
408 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
409 SORT_COMPARE CompareFunction
410 )
411{
412 EFI_STATUS Status;
413 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;
414 UINTN LoadOptionCount;
415 UINTN Index;
416 UINT16 *OptionOrder;
417
418 LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
419
420 //
421 // Insertion sort algorithm
422 //
423 PerformQuickSort (
424 LoadOption,
425 LoadOptionCount,
426 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
427 CompareFunction
428 );
429
430 //
431 // Create new ****Order variable
432 //
433 OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
434 ASSERT (OptionOrder != NULL);
435 for (Index = 0; Index < LoadOptionCount; Index++) {
436 OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
437 }
438
439 Status = gRT->SetVariable (
440 mBmLoadOptionOrderName[OptionType],
441 &gEfiGlobalVariableGuid,
442 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
443 LoadOptionCount * sizeof (UINT16),
444 OptionOrder
445 );
446 //
447 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
448 //
449 ASSERT_EFI_ERROR (Status);
450
451 FreePool (OptionOrder);
452 EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
453}
454
455/**
456 Initialize a load option.
457
458 @param Option Pointer to the load option to be initialized.
459 @param OptionNumber Option number of the load option.
460 @param OptionType Type of the load option.
461 @param Attributes Attributes of the load option.
462 @param Description Description of the load option.
463 @param FilePath Device path of the load option.
464 @param OptionalData Optional data of the load option.
465 @param OptionalDataSize Size of the optional data of the load option.
466
467 @retval EFI_SUCCESS The load option was initialized successfully.
468 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
469**/
470EFI_STATUS
471EFIAPI
472EfiBootManagerInitializeLoadOption (
473 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
474 IN UINTN OptionNumber,
475 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
476 IN UINT32 Attributes,
477 IN CHAR16 *Description,
478 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
479 IN UINT8 *OptionalData, OPTIONAL
480 IN UINT32 OptionalDataSize
481 )
482{
483 if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
484 return EFI_INVALID_PARAMETER;
485 }
486
487 if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
488 ((OptionalData == NULL) && (OptionalDataSize != 0))) {
489 return EFI_INVALID_PARAMETER;
490 }
491
492 if ((UINT32) OptionType >= LoadOptionTypeMax) {
493 return EFI_INVALID_PARAMETER;
494 }
495
496 ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
497 Option->OptionNumber = OptionNumber;
498 Option->OptionType = OptionType;
499 Option->Attributes = Attributes;
500 Option->Description = AllocateCopyPool (StrSize (Description), Description);
501 Option->FilePath = DuplicateDevicePath (FilePath);
502 if (OptionalData != NULL) {
503 Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
504 Option->OptionalDataSize = OptionalDataSize;
505 }
506
507 return EFI_SUCCESS;
508}
509
510
511/**
512 Return the index of the load option in the load option array.
513
514 The function consider two load options are equal when the
515 OptionType, Attributes, Description, FilePath and OptionalData are equal.
516
517 @param Key Pointer to the load option to be found.
518 @param Array Pointer to the array of load options to be found.
519 @param Count Number of entries in the Array.
520
521 @retval -1 Key wasn't found in the Array.
522 @retval 0 ~ Count-1 The index of the Key in the Array.
523**/
524INTN
525EFIAPI
526EfiBootManagerFindLoadOption (
527 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
528 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
529 IN UINTN Count
530 )
531{
532 UINTN Index;
533
534 for (Index = 0; Index < Count; Index++) {
535 if ((Key->OptionType == Array[Index].OptionType) &&
536 (Key->Attributes == Array[Index].Attributes) &&
537 (StrCmp (Key->Description, Array[Index].Description) == 0) &&
538 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
539 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
540 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
541 return (INTN) Index;
542 }
543 }
544
545 return -1;
546}
547
548/**
549 Delete the load option.
550
551 @param OptionNumber Indicate the option number of load option
552 @param OptionType Indicate the type of load option
553
554 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
555 @retval EFI_NOT_FOUND The load option cannot be found
556 @retval EFI_SUCCESS The load option was deleted
557 @retval others Status of RT->SetVariable()
558**/
559EFI_STATUS
560EFIAPI
561EfiBootManagerDeleteLoadOptionVariable (
562 IN UINTN OptionNumber,
563 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
564 )
565{
566 UINT16 *OptionOrder;
567 UINTN OptionOrderSize;
568 UINTN Index;
569 CHAR16 OptionName[BM_OPTION_NAME_LEN];
570
571 if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
572 return EFI_INVALID_PARAMETER;
573 }
574
575 if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
576 //
577 // If the associated *Order exists, firstly remove the reference in *Order for
578 // Driver####, SysPrep#### and Boot####.
579 //
580 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
581 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
582
583 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
584 if (OptionOrder[Index] == OptionNumber) {
585 OptionOrderSize -= sizeof (UINT16);
586 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
587 gRT->SetVariable (
588 mBmLoadOptionOrderName[OptionType],
589 &gEfiGlobalVariableGuid,
590 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
591 OptionOrderSize,
592 OptionOrder
593 );
594 break;
595 }
596 }
597 if (OptionOrder != NULL) {
598 FreePool (OptionOrder);
599 }
600 }
601
602 //
603 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
604 //
605 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);
606 return gRT->SetVariable (
607 OptionName,
608 &gEfiGlobalVariableGuid,
609 0,
610 0,
611 NULL
612 );
613}
614
615/**
616 Returns the size of a device path in bytes.
617
618 This function returns the size, in bytes, of the device path data structure
619 specified by DevicePath including the end of device path node. If DevicePath
620 is NULL, then 0 is returned. If the length of the device path is bigger than
621 MaxSize, also return 0 to indicate this is an invalidate device path.
622
623 @param DevicePath A pointer to a device path data structure.
624 @param MaxSize Max valid device path size. If big than this size,
625 return error.
626
627 @retval 0 An invalid device path.
628 @retval Others The size of a device path in bytes.
629
630**/
631UINTN
632BmGetDevicePathSizeEx (
633 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
634 IN UINTN MaxSize
635 )
636{
637 UINTN Size;
638 UINTN NodeSize;
639
640 if (DevicePath == NULL) {
641 return 0;
642 }
643
644 //
645 // Search for the end of the device path structure
646 //
647 Size = 0;
648 while (!IsDevicePathEnd (DevicePath)) {
649 NodeSize = DevicePathNodeLength (DevicePath);
650 if (NodeSize == 0) {
651 return 0;
652 }
653 Size += NodeSize;
654 if (Size > MaxSize) {
655 return 0;
656 }
657 DevicePath = NextDevicePathNode (DevicePath);
658 }
659 Size += DevicePathNodeLength (DevicePath);
660 if (Size > MaxSize) {
661 return 0;
662 }
663
664 return Size;
665}
666
667/**
668 Returns the length of a Null-terminated Unicode string. If the length is
669 bigger than MaxStringLen, return length 0 to indicate that this is an
670 invalidate string.
671
672 This function returns the number of Unicode characters in the Null-terminated
673 Unicode string specified by String.
674
675 If String is NULL, then ASSERT().
676 If String is not aligned on a 16-bit boundary, then ASSERT().
677
678 @param String A pointer to a Null-terminated Unicode string.
679 @param MaxStringLen Max string len in this string.
680
681 @retval 0 An invalid string.
682 @retval Others The length of String.
683
684**/
685UINTN
686BmStrSizeEx (
687 IN CONST CHAR16 *String,
688 IN UINTN MaxStringLen
689 )
690{
691 UINTN Length;
692
693 ASSERT (String != NULL && MaxStringLen != 0);
694 ASSERT (((UINTN) String & BIT0) == 0);
695
696 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
697
698 if (*String != L'\0' && MaxStringLen == Length) {
699 return 0;
700 }
701
702 return Length + 2;
703}
704
705/**
706 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
707 variable (VendorGuid/Name)
708
709 @param Variable The variable data.
710 @param VariableSize The variable size.
711
712 @retval TRUE The variable data is correct.
713 @retval FALSE The variable data is corrupted.
714
715**/
716BOOLEAN
717BmValidateOption (
718 UINT8 *Variable,
719 UINTN VariableSize
720 )
721{
722 UINT16 FilePathSize;
723 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
724 UINTN DescriptionSize;
725
726 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
727 return FALSE;
728 }
729
730 //
731 // Skip the option attribute
732 //
733 Variable += sizeof (UINT32);
734
735 //
736 // Get the option's device path size
737 //
738 FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
739 Variable += sizeof (UINT16);
740
741 //
742 // Get the option's description string size
743 //
744 DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
745 Variable += DescriptionSize;
746
747 //
748 // Get the option's device path
749 //
750 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
751
752 //
753 // Validation boot option variable.
754 //
755 if ((FilePathSize == 0) || (DescriptionSize == 0)) {
756 return FALSE;
757 }
758
759 if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
760 return FALSE;
761 }
762
763 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
764}
765
766/**
767 Check whether the VariableName is a valid load option variable name
768 and return the load option type and option number.
769
770 @param VariableName The name of the load option variable.
771 @param OptionType Return the load option type.
772 @param OptionNumber Return the load option number.
773
774 @retval TRUE The variable name is valid; The load option type and
775 load option number is returned.
776 @retval FALSE The variable name is NOT valid.
777**/
778BOOLEAN
779EFIAPI
780EfiBootManagerIsValidLoadOptionVariableName (
781 IN CHAR16 *VariableName,
782 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL,
783 OUT UINT16 *OptionNumber OPTIONAL
784 )
785{
786 UINTN VariableNameLen;
787 UINTN Index;
788 UINTN Uint;
789 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType;
790 UINT16 LocalOptionNumber;
791
792 if (VariableName == NULL) {
793 return FALSE;
794 }
795
796 VariableNameLen = StrLen (VariableName);
797
798 //
799 // Return FALSE when the variable name length is too small.
800 //
801 if (VariableNameLen <= 4) {
802 return FALSE;
803 }
804
805 //
806 // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.
807 //
808 for (LocalOptionType = 0; LocalOptionType < ARRAY_SIZE (mBmLoadOptionName); LocalOptionType++) {
809 if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[LocalOptionType])) &&
810 (StrnCmp (VariableName, mBmLoadOptionName[LocalOptionType], VariableNameLen - 4) == 0)
811 ) {
812 break;
813 }
814 }
815 if (LocalOptionType == ARRAY_SIZE (mBmLoadOptionName)) {
816 return FALSE;
817 }
818
819 //
820 // Return FALSE when the last four characters are not hex digits.
821 //
822 LocalOptionNumber = 0;
823 for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
824 Uint = BmCharToUint (VariableName[Index]);
825 if (Uint == -1) {
826 break;
827 } else {
828 LocalOptionNumber = (UINT16) Uint + LocalOptionNumber * 0x10;
829 }
830 }
831 if (Index != VariableNameLen) {
832 return FALSE;
833 }
834
835 if (OptionType != NULL) {
836 *OptionType = LocalOptionType;
837 }
838
839 if (OptionNumber != NULL) {
840 *OptionNumber = LocalOptionNumber;
841 }
842
843 return TRUE;
844}
845
846/**
847 Build the Boot#### or Driver#### option from the VariableName.
848
849 @param VariableName Variable name of the load option
850 @param VendorGuid Variable GUID of the load option
851 @param Option Return the load option.
852
853 @retval EFI_SUCCESS Get the option just been created
854 @retval EFI_NOT_FOUND Failed to get the new option
855
856**/
857EFI_STATUS
858EFIAPI
859EfiBootManagerVariableToLoadOptionEx (
860 IN CHAR16 *VariableName,
861 IN EFI_GUID *VendorGuid,
862 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
863 )
864{
865 EFI_STATUS Status;
866 UINT32 Attribute;
867 UINT16 FilePathSize;
868 UINT8 *Variable;
869 UINT8 *VariablePtr;
870 UINTN VariableSize;
871 EFI_DEVICE_PATH_PROTOCOL *FilePath;
872 UINT8 *OptionalData;
873 UINT32 OptionalDataSize;
874 CHAR16 *Description;
875 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
876 UINT16 OptionNumber;
877
878 if ((VariableName == NULL) || (Option == NULL)) {
879 return EFI_INVALID_PARAMETER;
880 }
881
882 if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
883 return EFI_INVALID_PARAMETER;
884 }
885
886 //
887 // Read the variable
888 //
889 GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
890 if (Variable == NULL) {
891 return EFI_NOT_FOUND;
892 }
893
894 //
895 // Validate *#### variable data.
896 //
897 if (!BmValidateOption(Variable, VariableSize)) {
898 FreePool (Variable);
899 return EFI_INVALID_PARAMETER;
900 }
901
902 //
903 // Get the option attribute
904 //
905 VariablePtr = Variable;
906 Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
907 VariablePtr += sizeof (UINT32);
908
909 //
910 // Get the option's device path size
911 //
912 FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
913 VariablePtr += sizeof (UINT16);
914
915 //
916 // Get the option's description string
917 //
918 Description = (CHAR16 *) VariablePtr;
919
920 //
921 // Get the option's description string size
922 //
923 VariablePtr += StrSize ((CHAR16 *) VariablePtr);
924
925 //
926 // Get the option's device path
927 //
928 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
929 VariablePtr += FilePathSize;
930
931 OptionalDataSize = (UINT32) (VariableSize - ((UINTN) VariablePtr - (UINTN) Variable));
932 if (OptionalDataSize == 0) {
933 OptionalData = NULL;
934 } else {
935 OptionalData = VariablePtr;
936 }
937
938 Status = EfiBootManagerInitializeLoadOption (
939 Option,
940 OptionNumber,
941 OptionType,
942 Attribute,
943 Description,
944 FilePath,
945 OptionalData,
946 OptionalDataSize
947 );
948 ASSERT_EFI_ERROR (Status);
949
950 CopyGuid (&Option->VendorGuid, VendorGuid);
951
952 FreePool (Variable);
953 return Status;
954}
955
956/**
957Build the Boot#### or Driver#### option from the VariableName.
958
959@param VariableName EFI Variable name indicate if it is Boot#### or Driver####
960@param Option Return the Boot#### or Driver#### option.
961
962@retval EFI_SUCCESS Get the option just been created
963@retval EFI_NOT_FOUND Failed to get the new option
964**/
965EFI_STATUS
966EFIAPI
967EfiBootManagerVariableToLoadOption (
968 IN CHAR16 *VariableName,
969 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
970 )
971{
972 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
973}
974
975typedef struct {
976 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
977 EFI_GUID *Guid;
978 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
979 UINTN OptionCount;
980} BM_COLLECT_LOAD_OPTIONS_PARAM;
981
982/**
983 Visitor function to collect the Platform Recovery load options or OS Recovery
984 load options from NV storage.
985
986 @param Name Variable name.
987 @param Guid Variable GUID.
988 @param Context The same context passed to BmForEachVariable.
989**/
990VOID
991BmCollectLoadOptions (
992 IN CHAR16 *Name,
993 IN EFI_GUID *Guid,
994 IN VOID *Context
995 )
996{
997 EFI_STATUS Status;
998 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
999 UINT16 OptionNumber;
1000 EFI_BOOT_MANAGER_LOAD_OPTION Option;
1001 UINTN Index;
1002 BM_COLLECT_LOAD_OPTIONS_PARAM *Param;
1003
1004 Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
1005
1006 if (CompareGuid (Guid, Param->Guid) && (
1007 Param->OptionType == LoadOptionTypePlatformRecovery &&
1008 EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
1009 OptionType == LoadOptionTypePlatformRecovery
1010 )) {
1011 Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
1012 if (!EFI_ERROR (Status)) {
1013 for (Index = 0; Index < Param->OptionCount; Index++) {
1014 if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
1015 break;
1016 }
1017 }
1018 Param->Options = ReallocatePool (
1019 Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
1020 (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
1021 Param->Options
1022 );
1023 ASSERT (Param->Options != NULL);
1024 CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1025 CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1026 Param->OptionCount++;
1027 }
1028 }
1029}
1030
1031/**
1032 Returns an array of load options based on the EFI variable
1033 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
1034 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
1035
1036 @param LoadOptionCount Returns number of entries in the array.
1037 @param LoadOptionType The type of the load option.
1038
1039 @retval NULL No load options exist.
1040 @retval !NULL Array of load option entries.
1041
1042**/
1043EFI_BOOT_MANAGER_LOAD_OPTION *
1044EFIAPI
1045EfiBootManagerGetLoadOptions (
1046 OUT UINTN *OptionCount,
1047 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
1048 )
1049{
1050 EFI_STATUS Status;
1051 UINT16 *OptionOrder;
1052 UINTN OptionOrderSize;
1053 UINTN Index;
1054 UINTN OptionIndex;
1055 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
1056 CHAR16 OptionName[BM_OPTION_NAME_LEN];
1057 UINT16 OptionNumber;
1058 BM_COLLECT_LOAD_OPTIONS_PARAM Param;
1059
1060 *OptionCount = 0;
1061 Options = NULL;
1062
1063 if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
1064 //
1065 // Read the BootOrder, or DriverOrder variable.
1066 //
1067 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
1068 if (OptionOrder == NULL) {
1069 return NULL;
1070 }
1071
1072 *OptionCount = OptionOrderSize / sizeof (UINT16);
1073
1074 Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1075 ASSERT (Options != NULL);
1076
1077 OptionIndex = 0;
1078 for (Index = 0; Index < *OptionCount; Index++) {
1079 OptionNumber = OptionOrder[Index];
1080 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
1081
1082 Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
1083 if (EFI_ERROR (Status)) {
1084 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
1085 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
1086 } else {
1087 ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
1088 OptionIndex++;
1089 }
1090 }
1091
1092 if (OptionOrder != NULL) {
1093 FreePool (OptionOrder);
1094 }
1095
1096 if (OptionIndex < *OptionCount) {
1097 Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
1098 ASSERT (Options != NULL);
1099 *OptionCount = OptionIndex;
1100 }
1101
1102 } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
1103 Param.OptionType = LoadOptionTypePlatformRecovery;
1104 Param.Options = NULL;
1105 Param.OptionCount = 0;
1106 Param.Guid = &gEfiGlobalVariableGuid;
1107
1108 BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
1109
1110 *OptionCount = Param.OptionCount;
1111 Options = Param.Options;
1112 }
1113
1114 return Options;
1115}
1116
1117/**
1118 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1119
1120 @param LoadOption Pointer to boot option to Free.
1121
1122 @return EFI_SUCCESS BootOption was freed
1123 @return EFI_NOT_FOUND BootOption == NULL
1124
1125**/
1126EFI_STATUS
1127EFIAPI
1128EfiBootManagerFreeLoadOption (
1129 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1130 )
1131{
1132 if (LoadOption == NULL) {
1133 return EFI_NOT_FOUND;
1134 }
1135
1136 if (LoadOption->Description != NULL) {
1137 FreePool (LoadOption->Description);
1138 }
1139 if (LoadOption->FilePath != NULL) {
1140 FreePool (LoadOption->FilePath);
1141 }
1142 if (LoadOption->OptionalData != NULL) {
1143 FreePool (LoadOption->OptionalData);
1144 }
1145
1146 return EFI_SUCCESS;
1147}
1148
1149/**
1150 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1151 EfiBootManagerGetLoadOptions().
1152
1153 @param Option Pointer to boot option array to free.
1154 @param OptionCount Number of array entries in BootOption
1155
1156 @return EFI_SUCCESS BootOption was freed
1157 @return EFI_NOT_FOUND BootOption == NULL
1158
1159**/
1160EFI_STATUS
1161EFIAPI
1162EfiBootManagerFreeLoadOptions (
1163 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
1164 IN UINTN OptionCount
1165 )
1166{
1167 UINTN Index;
1168
1169 if (Option == NULL) {
1170 return EFI_NOT_FOUND;
1171 }
1172
1173 for (Index = 0;Index < OptionCount; Index++) {
1174 EfiBootManagerFreeLoadOption (&Option[Index]);
1175 }
1176
1177 FreePool (Option);
1178
1179 return EFI_SUCCESS;
1180}
1181
1182/**
1183 Return whether the PE header of the load option is valid or not.
1184
1185 @param[in] Type The load option type.
1186 It's used to check whether the load option is valid.
1187 When it's LoadOptionTypeMax, the routine only guarantees
1188 the load option is a valid PE image but doesn't guarantee
1189 the PE's subsystem type is valid.
1190 @param[in] FileBuffer The PE file buffer of the load option.
1191 @param[in] FileSize The size of the load option file.
1192
1193 @retval TRUE The PE header of the load option is valid.
1194 @retval FALSE The PE header of the load option is not valid.
1195**/
1196BOOLEAN
1197BmIsLoadOptionPeHeaderValid (
1198 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
1199 IN VOID *FileBuffer,
1200 IN UINTN FileSize
1201 )
1202{
1203 EFI_IMAGE_DOS_HEADER *DosHeader;
1204 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;
1205 EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;
1206 UINT16 Subsystem;
1207
1208 if (FileBuffer == NULL || FileSize == 0) {
1209 return FALSE;
1210 }
1211
1212#ifdef VBOX
1213 /*
1214 * Check for Fat/Universal EFI binaries provided by older macOS versions
1215 * (Mountain Lion and older).
1216 *
1217 * @todo More checks here? (VBoxPeCoffLib will do more thorough checks
1218 * when the image is actually loaded).
1219 */
1220 if (*(UINT32 *)FileBuffer == 0x0ef1fab9)
1221 return TRUE;
1222#endif
1223
1224 //
1225 // Read dos header
1226 //
1227 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
1228 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
1229 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
1230 ) {
1231 //
1232 // Read and check PE signature
1233 //
1234 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
1235 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
1236 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
1237 ) {
1238 //
1239 // Check PE32 or PE32+ magic, and machine type
1240 //
1241 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
1242 if (OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
1243 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1244 //
1245 // Check the Subsystem:
1246 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1247 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1248 //
1249 Subsystem = OptionalHeader->Subsystem;
1250 if ((Type == LoadOptionTypeMax) ||
1251 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
1252 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
1253 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1254 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1255 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
1256 ) {
1257 return TRUE;
1258 }
1259 }
1260 }
1261 }
1262
1263 return FALSE;
1264}
1265
1266/**
1267 Return the next matched load option buffer.
1268 The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
1269 load option is read.
1270
1271 @param Type The load option type.
1272 It's used to check whether the load option is valid.
1273 When it's LoadOptionTypeMax, the routine only guarantees
1274 the load option is a valid PE image but doesn't guarantee
1275 the PE's subsystem type is valid.
1276 @param FilePath The device path pointing to a load option.
1277 It could be a short-form device path.
1278 @param FullPath Return the next full device path of the load option after
1279 short-form device path expanding.
1280 Caller is responsible to free it.
1281 NULL to return the first matched full device path.
1282 @param FileSize Return the load option size.
1283
1284 @return The load option buffer. Caller is responsible to free the memory.
1285**/
1286VOID *
1287BmGetNextLoadOptionBuffer (
1288 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
1289 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1290 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1291 OUT UINTN *FileSize
1292 )
1293{
1294 VOID *FileBuffer;
1295 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
1296 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
1297 UINTN LocalFileSize;
1298 UINT32 AuthenticationStatus;
1299 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
1300
1301 LocalFileSize = 0;
1302 FileBuffer = NULL;
1303 CurFullPath = *FullPath;
1304 do {
1305 PreFullPath = CurFullPath;
1306 CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);
1307 //
1308 // Only free the full path created *inside* this routine
1309 //
1310 if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {
1311 FreePool (PreFullPath);
1312 }
1313 if (CurFullPath == NULL) {
1314 break;
1315 }
1316 FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);
1317 if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {
1318 //
1319 // Free the RAM disk file system if the load option is invalid.
1320 //
1321 RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
1322 if (RamDiskDevicePath != NULL) {
1323 BmDestroyRamDisk (RamDiskDevicePath);
1324 FreePool (RamDiskDevicePath);
1325 }
1326
1327 //
1328 // Free the invalid load option buffer.
1329 //
1330 FreePool (FileBuffer);
1331 FileBuffer = NULL;
1332 }
1333 } while (FileBuffer == NULL);
1334
1335 if (FileBuffer == NULL) {
1336 CurFullPath = NULL;
1337 LocalFileSize = 0;
1338 }
1339
1340 DEBUG ((DEBUG_INFO, "[Bds] Expand "));
1341 BmPrintDp (FilePath);
1342 DEBUG ((DEBUG_INFO, " -> "));
1343 BmPrintDp (CurFullPath);
1344 DEBUG ((DEBUG_INFO, "\n"));
1345
1346 *FullPath = CurFullPath;
1347 *FileSize = LocalFileSize;
1348 return FileBuffer;
1349}
1350
1351/**
1352 Process (load and execute) the load option.
1353
1354 @param LoadOption Pointer to the load option.
1355
1356 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1357 or the load option file path doesn't point to a valid file.
1358 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1359 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1360**/
1361EFI_STATUS
1362EFIAPI
1363EfiBootManagerProcessLoadOption (
1364 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1365 )
1366{
1367 EFI_STATUS Status;
1368 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
1369 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
1370 EFI_HANDLE ImageHandle;
1371 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1372 VOID *FileBuffer;
1373 UINTN FileSize;
1374
1375 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
1376 return EFI_INVALID_PARAMETER;
1377 }
1378
1379 if (LoadOption->OptionType == LoadOptionTypeBoot) {
1380 return EFI_UNSUPPORTED;
1381 }
1382
1383 //
1384 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1385 // the boot manager will not automatically load the option.
1386 //
1387 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
1388 return EFI_SUCCESS;
1389 }
1390
1391 //
1392 // Load and start the load option.
1393 //
1394 DEBUG ((
1395 DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",
1396 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,
1397 LoadOption->Description
1398 ));
1399 ImageHandle = NULL;
1400 CurFullPath = NULL;
1401 EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);
1402
1403 //
1404 // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
1405 //
1406 while (TRUE) {
1407 Status = EFI_INVALID_PARAMETER;
1408 PreFullPath = CurFullPath;
1409 FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);
1410 if (PreFullPath != NULL) {
1411 FreePool (PreFullPath);
1412 }
1413 if (FileBuffer == NULL) {
1414 break;
1415 }
1416 Status = gBS->LoadImage (
1417 FALSE,
1418 gImageHandle,
1419 CurFullPath,
1420 FileBuffer,
1421 FileSize,
1422 &ImageHandle
1423 );
1424 FreePool (FileBuffer);
1425
1426 if (EFI_ERROR (Status)) {
1427 //
1428 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1429 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1430 // If the caller doesn't have the option to defer the execution of an image, we should
1431 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1432 //
1433 if (Status == EFI_SECURITY_VIOLATION) {
1434 gBS->UnloadImage (ImageHandle);
1435 }
1436 } else {
1437 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
1438 ASSERT_EFI_ERROR (Status);
1439
1440 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
1441 ImageInfo->LoadOptions = LoadOption->OptionalData;
1442 //
1443 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1444 //
1445 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
1446
1447 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
1448 DEBUG ((
1449 DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
1450 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
1451 ));
1452
1453 //
1454 // Clear the Watchdog Timer after the image returns
1455 //
1456 gBS->SetWatchdogTimer (0, 0, 0, NULL);
1457
1458 if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {
1459 break;
1460 }
1461 }
1462 }
1463
1464 if (CurFullPath != NULL) {
1465 FreePool (CurFullPath);
1466 }
1467
1468 return Status;
1469}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette