]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg: Change OPTIONAL keyword usage style
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmLoadOption.c
1 /** @file
2 Load option library functions which relate with creating and processing load options.
3
4 Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "InternalBm.h"
11
12 GLOBAL_REMOVE_IF_UNREFERENCED
13 CHAR16 *mBmLoadOptionName[] = {
14 L"Driver",
15 L"SysPrep",
16 L"Boot",
17 L"PlatformRecovery"
18 };
19
20 GLOBAL_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 **/
34 VOID
35 BmForEachVariable (
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 **/
81 EFI_STATUS
82 BmGetFreeOptionNumber (
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 **/
161 EFI_STATUS
162 EFIAPI
163 EfiBootManagerLoadOptionToVariable (
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[];
199 TODO: FilePathList[] IS:
200 A packed array of UEFI device paths. The first element of the
201 array is a device path that describes the device and location of the
202 Image for this load option. The FilePathList[0] is specific
203 to the device type. Other device paths may optionally exist in the
204 FilePathList, but their usage is OSV specific. Each element
205 in the array is variable length, and ends at the device path end
206 structure.
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 **/
271 EFI_STATUS
272 BmAddOptionNumberToOrderVariable (
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 **/
345 EFI_STATUS
346 EFIAPI
347 EfiBootManagerAddLoadOptionVariable (
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 **/
405 VOID
406 EFIAPI
407 EfiBootManagerSortLoadOptionVariable (
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 **/
470 EFI_STATUS
471 EFIAPI
472 EfiBootManagerInitializeLoadOption (
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 **/
524 INTN
525 EFIAPI
526 EfiBootManagerFindLoadOption (
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 **/
559 EFI_STATUS
560 EFIAPI
561 EfiBootManagerDeleteLoadOptionVariable (
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 **/
631 UINTN
632 BmGetDevicePathSizeEx (
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 **/
685 UINTN
686 BmStrSizeEx (
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 **/
716 BOOLEAN
717 BmValidateOption (
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 **/
778 BOOLEAN
779 EFIAPI
780 EfiBootManagerIsValidLoadOptionVariableName (
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 **/
857 EFI_STATUS
858 EFIAPI
859 EfiBootManagerVariableToLoadOptionEx (
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 /**
957 Build 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 **/
965 EFI_STATUS
966 EFIAPI
967 EfiBootManagerVariableToLoadOption (
968 IN CHAR16 *VariableName,
969 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
970 )
971 {
972 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
973 }
974
975 typedef 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 **/
990 VOID
991 BmCollectLoadOptions (
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 **/
1043 EFI_BOOT_MANAGER_LOAD_OPTION *
1044 EFIAPI
1045 EfiBootManagerGetLoadOptions (
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 ((DEBUG_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 **/
1126 EFI_STATUS
1127 EFIAPI
1128 EfiBootManagerFreeLoadOption (
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 **/
1160 EFI_STATUS
1161 EFIAPI
1162 EfiBootManagerFreeLoadOptions (
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 **/
1196 BOOLEAN
1197 BmIsLoadOptionPeHeaderValid (
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 //
1213 // Read dos header
1214 //
1215 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
1216 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
1217 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
1218 ) {
1219 //
1220 // Read and check PE signature
1221 //
1222 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
1223 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
1224 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
1225 ) {
1226 //
1227 // Check PE32 or PE32+ magic, and machine type
1228 //
1229 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
1230 if (OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
1231 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1232 //
1233 // Check the Subsystem:
1234 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1235 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1236 //
1237 Subsystem = OptionalHeader->Subsystem;
1238 if ((Type == LoadOptionTypeMax) ||
1239 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
1240 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
1241 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1242 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1243 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
1244 ) {
1245 return TRUE;
1246 }
1247 }
1248 }
1249 }
1250
1251 return FALSE;
1252 }
1253
1254 /**
1255 Return the next matched load option buffer.
1256 The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid
1257 load option is read.
1258
1259 @param Type The load option type.
1260 It's used to check whether the load option is valid.
1261 When it's LoadOptionTypeMax, the routine only guarantees
1262 the load option is a valid PE image but doesn't guarantee
1263 the PE's subsystem type is valid.
1264 @param FilePath The device path pointing to a load option.
1265 It could be a short-form device path.
1266 @param FullPath Return the next full device path of the load option after
1267 short-form device path expanding.
1268 Caller is responsible to free it.
1269 NULL to return the first matched full device path.
1270 @param FileSize Return the load option size.
1271
1272 @return The load option buffer. Caller is responsible to free the memory.
1273 **/
1274 VOID *
1275 BmGetNextLoadOptionBuffer (
1276 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
1277 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1278 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
1279 OUT UINTN *FileSize
1280 )
1281 {
1282 VOID *FileBuffer;
1283 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
1284 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
1285 UINTN LocalFileSize;
1286 UINT32 AuthenticationStatus;
1287 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
1288
1289 LocalFileSize = 0;
1290 FileBuffer = NULL;
1291 CurFullPath = *FullPath;
1292 do {
1293 PreFullPath = CurFullPath;
1294 CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);
1295 //
1296 // Only free the full path created *inside* this routine
1297 //
1298 if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {
1299 FreePool (PreFullPath);
1300 }
1301 if (CurFullPath == NULL) {
1302 break;
1303 }
1304 FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);
1305 if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {
1306 //
1307 // Free the RAM disk file system if the load option is invalid.
1308 //
1309 RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
1310 if (RamDiskDevicePath != NULL) {
1311 BmDestroyRamDisk (RamDiskDevicePath);
1312 FreePool (RamDiskDevicePath);
1313 }
1314
1315 //
1316 // Free the invalid load option buffer.
1317 //
1318 FreePool (FileBuffer);
1319 FileBuffer = NULL;
1320 }
1321 } while (FileBuffer == NULL);
1322
1323 if (FileBuffer == NULL) {
1324 CurFullPath = NULL;
1325 LocalFileSize = 0;
1326 }
1327
1328 DEBUG ((DEBUG_INFO, "[Bds] Expand "));
1329 BmPrintDp (FilePath);
1330 DEBUG ((DEBUG_INFO, " -> "));
1331 BmPrintDp (CurFullPath);
1332 DEBUG ((DEBUG_INFO, "\n"));
1333
1334 *FullPath = CurFullPath;
1335 *FileSize = LocalFileSize;
1336 return FileBuffer;
1337 }
1338
1339 /**
1340 Process (load and execute) the load option.
1341
1342 @param LoadOption Pointer to the load option.
1343
1344 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1345 or the load option file path doesn't point to a valid file.
1346 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1347 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1348 **/
1349 EFI_STATUS
1350 EFIAPI
1351 EfiBootManagerProcessLoadOption (
1352 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1353 )
1354 {
1355 EFI_STATUS Status;
1356 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
1357 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
1358 EFI_HANDLE ImageHandle;
1359 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1360 VOID *FileBuffer;
1361 UINTN FileSize;
1362
1363 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
1364 return EFI_INVALID_PARAMETER;
1365 }
1366
1367 if (LoadOption->OptionType == LoadOptionTypeBoot) {
1368 return EFI_UNSUPPORTED;
1369 }
1370
1371 //
1372 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1373 // the boot manager will not automatically load the option.
1374 //
1375 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
1376 return EFI_SUCCESS;
1377 }
1378
1379 //
1380 // Load and start the load option.
1381 //
1382 DEBUG ((
1383 DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",
1384 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,
1385 LoadOption->Description
1386 ));
1387 ImageHandle = NULL;
1388 CurFullPath = NULL;
1389 EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);
1390
1391 //
1392 // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.
1393 //
1394 while (TRUE) {
1395 Status = EFI_INVALID_PARAMETER;
1396 PreFullPath = CurFullPath;
1397 FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);
1398 if (PreFullPath != NULL) {
1399 FreePool (PreFullPath);
1400 }
1401 if (FileBuffer == NULL) {
1402 break;
1403 }
1404 Status = gBS->LoadImage (
1405 FALSE,
1406 gImageHandle,
1407 CurFullPath,
1408 FileBuffer,
1409 FileSize,
1410 &ImageHandle
1411 );
1412 FreePool (FileBuffer);
1413
1414 if (EFI_ERROR (Status)) {
1415 //
1416 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1417 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1418 // If the caller doesn't have the option to defer the execution of an image, we should
1419 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1420 //
1421 if (Status == EFI_SECURITY_VIOLATION) {
1422 gBS->UnloadImage (ImageHandle);
1423 }
1424 } else {
1425 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
1426 ASSERT_EFI_ERROR (Status);
1427
1428 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
1429 ImageInfo->LoadOptions = LoadOption->OptionalData;
1430 //
1431 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1432 //
1433 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
1434
1435 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
1436 DEBUG ((
1437 DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",
1438 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
1439 ));
1440
1441 //
1442 // Clear the Watchdog Timer after the image returns
1443 //
1444 gBS->SetWatchdogTimer (0, 0, 0, NULL);
1445
1446 if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {
1447 break;
1448 }
1449 }
1450 }
1451
1452 if (CurFullPath != NULL) {
1453 FreePool (CurFullPath);
1454 }
1455
1456 return Status;
1457 }