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