]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg: Add Platform recovery support
[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 - 2015, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "InternalBm.h"
17
18 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 return gRT->SetVariable (
254 OptionName,
255 &gEfiGlobalVariableGuid,
256 VariableAttributes,
257 VariableSize,
258 Variable
259 );
260 }
261
262 /**
263 Update order variable .
264
265 @param OptionOrderName Order variable name which need to be updated.
266 @param OptionNumber Option number for the new option.
267 @param Position Position of the new load option to put in the ****Order variable.
268
269 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
270 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
271 @retval EFI_STATUS Return the status of gRT->SetVariable ().
272
273 **/
274 EFI_STATUS
275 BmAddOptionNumberToOrderVariable (
276 IN CHAR16 *OptionOrderName,
277 IN UINT16 OptionNumber,
278 IN UINTN Position
279 )
280 {
281 EFI_STATUS Status;
282 UINTN Index;
283 UINT16 *OptionOrder;
284 UINT16 *NewOptionOrder;
285 UINTN OptionOrderSize;
286 //
287 // Update the option order variable
288 //
289 GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
290 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
291
292 Status = EFI_SUCCESS;
293 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
294 if (OptionOrder[Index] == OptionNumber) {
295 Status = EFI_ALREADY_STARTED;
296 break;
297 }
298 }
299
300 if (!EFI_ERROR (Status)) {
301 Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
302
303 NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
304 ASSERT (NewOptionOrder != NULL);
305 if (OptionOrderSize != 0) {
306 CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
307 CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
308 }
309 NewOptionOrder[Position] = OptionNumber;
310
311 Status = gRT->SetVariable (
312 OptionOrderName,
313 &gEfiGlobalVariableGuid,
314 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
315 OptionOrderSize + sizeof (UINT16),
316 NewOptionOrder
317 );
318 FreePool (NewOptionOrder);
319 }
320
321 if (OptionOrder != NULL) {
322 FreePool (OptionOrder);
323 }
324
325 return Status;
326 }
327
328 /**
329 This function will register the new Boot####, Driver#### or SysPrep#### option.
330 After the *#### is updated, the *Order will also be updated.
331
332 @param Option Pointer to load option to add.
333 @param Position Position of the new load option to put in the ****Order variable.
334
335 @retval EFI_SUCCESS The *#### have been successfully registered.
336 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
337 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
338 Note: this API only adds new load option, no replacement support.
339 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
340 option number specified in the Option is LoadOptionNumberUnassigned.
341 @retval EFI_STATUS Return the status of gRT->SetVariable ().
342
343 **/
344 EFI_STATUS
345 EFIAPI
346 EfiBootManagerAddLoadOptionVariable (
347 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
348 IN UINTN Position
349 )
350 {
351 EFI_STATUS Status;
352 UINT16 OptionNumber;
353
354 if (Option == NULL) {
355 return EFI_INVALID_PARAMETER;
356 }
357
358 if (Option->OptionType != LoadOptionTypeDriver &&
359 Option->OptionType != LoadOptionTypeSysPrep &&
360 Option->OptionType != LoadOptionTypeBoot
361 ) {
362 return EFI_INVALID_PARAMETER;
363 }
364
365 //
366 // Get the free option number if the option number is unassigned
367 //
368 if (Option->OptionNumber == LoadOptionNumberUnassigned) {
369 Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
370 if (EFI_ERROR (Status)) {
371 return Status;
372 }
373 Option->OptionNumber = OptionNumber;
374 }
375
376 if (Option->OptionNumber >= LoadOptionNumberMax) {
377 return EFI_INVALID_PARAMETER;
378 }
379
380 Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
381 if (!EFI_ERROR (Status)) {
382 //
383 // Save the Boot#### or Driver#### variable
384 //
385 Status = EfiBootManagerLoadOptionToVariable (Option);
386 if (EFI_ERROR (Status)) {
387 //
388 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
389 //
390 EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
391 }
392 }
393
394 return Status;
395 }
396
397 /**
398 Sort the load option. The DriverOrder or BootOrder will be re-created to
399 reflect the new order.
400
401 @param OptionType Load option type
402 @param CompareFunction The comparator
403 **/
404 VOID
405 EFIAPI
406 EfiBootManagerSortLoadOptionVariable (
407 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
408 SORT_COMPARE CompareFunction
409 )
410 {
411 EFI_STATUS Status;
412 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;
413 UINTN LoadOptionCount;
414 UINTN Index;
415 UINT16 *OptionOrder;
416
417 LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
418
419 //
420 // Insertion sort algorithm
421 //
422 PerformQuickSort (
423 LoadOption,
424 LoadOptionCount,
425 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
426 CompareFunction
427 );
428
429 //
430 // Create new ****Order variable
431 //
432 OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
433 ASSERT (OptionOrder != NULL);
434 for (Index = 0; Index < LoadOptionCount; Index++) {
435 OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
436 }
437
438 Status = gRT->SetVariable (
439 mBmLoadOptionOrderName[OptionType],
440 &gEfiGlobalVariableGuid,
441 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
442 LoadOptionCount * sizeof (UINT16),
443 OptionOrder
444 );
445 //
446 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
447 //
448 ASSERT_EFI_ERROR (Status);
449
450 FreePool (OptionOrder);
451 EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
452 }
453
454 /**
455 Initialize a load option.
456
457 @param Option Pointer to the load option to be initialized.
458 @param OptionNumber Option number of the load option.
459 @param OptionType Type of the load option.
460 @param Attributes Attributes of the load option.
461 @param Description Description of the load option.
462 @param FilePath Device path of the load option.
463 @param OptionalData Optional data of the load option.
464 @param OptionalDataSize Size of the optional data of the load option.
465
466 @retval EFI_SUCCESS The load option was initialized successfully.
467 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
468 **/
469 EFI_STATUS
470 EFIAPI
471 EfiBootManagerInitializeLoadOption (
472 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
473 IN UINTN OptionNumber,
474 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
475 IN UINT32 Attributes,
476 IN CHAR16 *Description,
477 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
478 IN UINT8 *OptionalData, OPTIONAL
479 IN UINT32 OptionalDataSize
480 )
481 {
482 if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
483 return EFI_INVALID_PARAMETER;
484 }
485
486 if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
487 ((OptionalData == NULL) && (OptionalDataSize != 0))) {
488 return EFI_INVALID_PARAMETER;
489 }
490
491 if ((UINT32) OptionType >= LoadOptionTypeMax) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
496 Option->OptionNumber = OptionNumber;
497 Option->OptionType = OptionType;
498 Option->Attributes = Attributes;
499 Option->Description = AllocateCopyPool (StrSize (Description), Description);
500 Option->FilePath = DuplicateDevicePath (FilePath);
501 if (OptionalData != NULL) {
502 Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
503 Option->OptionalDataSize = OptionalDataSize;
504 }
505
506 return EFI_SUCCESS;
507 }
508
509
510 /**
511 Return the index of the load option in the load option array.
512
513 The function consider two load options are equal when the
514 OptionType, Attributes, Description, FilePath and OptionalData are equal.
515
516 @param Key Pointer to the load option to be found.
517 @param Array Pointer to the array of load options to be found.
518 @param Count Number of entries in the Array.
519
520 @retval -1 Key wasn't found in the Array.
521 @retval 0 ~ Count-1 The index of the Key in the Array.
522 **/
523 INTN
524 EFIAPI
525 EfiBootManagerFindLoadOption (
526 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
527 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
528 IN UINTN Count
529 )
530 {
531 UINTN Index;
532
533 for (Index = 0; Index < Count; Index++) {
534 if ((Key->OptionType == Array[Index].OptionType) &&
535 (Key->Attributes == Array[Index].Attributes) &&
536 (StrCmp (Key->Description, Array[Index].Description) == 0) &&
537 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
538 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
539 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
540 return (INTN) Index;
541 }
542 }
543
544 return -1;
545 }
546
547 /**
548 Delete the load option.
549
550 @param OptionNumber Indicate the option number of load option
551 @param OptionType Indicate the type of load option
552
553 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
554 @retval EFI_NOT_FOUND The load option cannot be found
555 @retval EFI_SUCCESS The load option was deleted
556 @retval others Status of RT->SetVariable()
557 **/
558 EFI_STATUS
559 EFIAPI
560 EfiBootManagerDeleteLoadOptionVariable (
561 IN UINTN OptionNumber,
562 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
563 )
564 {
565 UINT16 *OptionOrder;
566 UINTN OptionOrderSize;
567 EFI_STATUS Status;
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 Status = EFI_NOT_FOUND;
576
577 if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
578 //
579 // If the associated *Order exists, just remove the reference in *Order.
580 //
581 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
582 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
583
584 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
585 if (OptionOrder[Index] == OptionNumber) {
586 OptionOrderSize -= sizeof (UINT16);
587 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
588 Status = gRT->SetVariable (
589 mBmLoadOptionOrderName[OptionType],
590 &gEfiGlobalVariableGuid,
591 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
592 OptionOrderSize,
593 OptionOrder
594 );
595 break;
596 }
597 }
598 if (OptionOrder != NULL) {
599 FreePool (OptionOrder);
600 }
601 } else if (OptionType == LoadOptionTypePlatformRecovery) {
602 //
603 // PlatformRecovery#### doesn't have assiciated PlatformRecoveryOrder, remove the PlatformRecovery#### itself.
604 //
605 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);
606 Status = gRT->SetVariable (
607 OptionName,
608 &gEfiGlobalVariableGuid,
609 0,
610 0,
611 NULL
612 );
613 }
614
615 return Status;
616 }
617
618 /**
619 Returns the size of a device path in bytes.
620
621 This function returns the size, in bytes, of the device path data structure
622 specified by DevicePath including the end of device path node. If DevicePath
623 is NULL, then 0 is returned. If the length of the device path is bigger than
624 MaxSize, also return 0 to indicate this is an invalidate device path.
625
626 @param DevicePath A pointer to a device path data structure.
627 @param MaxSize Max valid device path size. If big than this size,
628 return error.
629
630 @retval 0 An invalid device path.
631 @retval Others The size of a device path in bytes.
632
633 **/
634 UINTN
635 BmGetDevicePathSizeEx (
636 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
637 IN UINTN MaxSize
638 )
639 {
640 UINTN Size;
641 UINTN NodeSize;
642
643 if (DevicePath == NULL) {
644 return 0;
645 }
646
647 //
648 // Search for the end of the device path structure
649 //
650 Size = 0;
651 while (!IsDevicePathEnd (DevicePath)) {
652 NodeSize = DevicePathNodeLength (DevicePath);
653 if (NodeSize == 0) {
654 return 0;
655 }
656 Size += NodeSize;
657 if (Size > MaxSize) {
658 return 0;
659 }
660 DevicePath = NextDevicePathNode (DevicePath);
661 }
662 Size += DevicePathNodeLength (DevicePath);
663 if (Size > MaxSize) {
664 return 0;
665 }
666
667 return Size;
668 }
669
670 /**
671 Returns the length of a Null-terminated Unicode string. If the length is
672 bigger than MaxStringLen, return length 0 to indicate that this is an
673 invalidate string.
674
675 This function returns the number of Unicode characters in the Null-terminated
676 Unicode string specified by String.
677
678 If String is NULL, then ASSERT().
679 If String is not aligned on a 16-bit boundary, then ASSERT().
680
681 @param String A pointer to a Null-terminated Unicode string.
682 @param MaxStringLen Max string len in this string.
683
684 @retval 0 An invalid string.
685 @retval Others The length of String.
686
687 **/
688 UINTN
689 BmStrSizeEx (
690 IN CONST CHAR16 *String,
691 IN UINTN MaxStringLen
692 )
693 {
694 UINTN Length;
695
696 ASSERT (String != NULL && MaxStringLen != 0);
697 ASSERT (((UINTN) String & BIT0) == 0);
698
699 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
700
701 if (*String != L'\0' && MaxStringLen == Length) {
702 return 0;
703 }
704
705 return Length + 2;
706 }
707
708 /**
709 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
710 variable (VendorGuid/Name)
711
712 @param Variable The variable data.
713 @param VariableSize The variable size.
714
715 @retval TRUE The variable data is correct.
716 @retval FALSE The variable data is corrupted.
717
718 **/
719 BOOLEAN
720 BmValidateOption (
721 UINT8 *Variable,
722 UINTN VariableSize
723 )
724 {
725 UINT16 FilePathSize;
726 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
727 UINTN DescriptionSize;
728
729 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
730 return FALSE;
731 }
732
733 //
734 // Skip the option attribute
735 //
736 Variable += sizeof (UINT32);
737
738 //
739 // Get the option's device path size
740 //
741 FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
742 Variable += sizeof (UINT16);
743
744 //
745 // Get the option's description string size
746 //
747 DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
748 Variable += DescriptionSize;
749
750 //
751 // Get the option's device path
752 //
753 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
754
755 //
756 // Validation boot option variable.
757 //
758 if ((FilePathSize == 0) || (DescriptionSize == 0)) {
759 return FALSE;
760 }
761
762 if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
763 return FALSE;
764 }
765
766 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
767 }
768
769 /**
770 Check whether the VariableName is a valid load option variable name
771 and return the load option type and option number.
772
773 @param VariableName The name of the load option variable.
774 @param OptionType Return the load option type.
775 @param OptionNumber Return the load option number.
776
777 @retval TRUE The variable name is valid; The load option type and
778 load option number is returned.
779 @retval FALSE The variable name is NOT valid.
780 **/
781 BOOLEAN
782 BmIsValidLoadOptionVariableName (
783 IN CHAR16 *VariableName,
784 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
785 OUT UINT16 *OptionNumber
786 )
787 {
788 UINTN VariableNameLen;
789 UINTN Index;
790 UINTN Uint;
791
792 VariableNameLen = StrLen (VariableName);
793
794 if (VariableNameLen <= 4) {
795 return FALSE;
796 }
797
798 for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
799 if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
800 (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
801 ) {
802 break;
803 }
804 }
805
806 if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
807 return FALSE;
808 }
809
810 *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
811 *OptionNumber = 0;
812 for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
813 Uint = BmCharToUint (VariableName[Index]);
814 if (Uint == -1) {
815 break;
816 } else {
817 *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
818 }
819 }
820
821 return (BOOLEAN) (Index == VariableNameLen);
822 }
823
824 /**
825 Build the Boot#### or Driver#### option from the VariableName.
826
827 @param VariableName Variable name of the load option
828 @param VendorGuid Variable GUID of the load option
829 @param Option Return the load option.
830
831 @retval EFI_SUCCESS Get the option just been created
832 @retval EFI_NOT_FOUND Failed to get the new option
833
834 **/
835 EFI_STATUS
836 EFIAPI
837 EfiBootManagerVariableToLoadOptionEx (
838 IN CHAR16 *VariableName,
839 IN EFI_GUID *VendorGuid,
840 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
841 )
842 {
843 EFI_STATUS Status;
844 UINT32 Attribute;
845 UINT16 FilePathSize;
846 UINT8 *Variable;
847 UINT8 *VariablePtr;
848 UINTN VariableSize;
849 EFI_DEVICE_PATH_PROTOCOL *FilePath;
850 UINT8 *OptionalData;
851 UINT32 OptionalDataSize;
852 CHAR16 *Description;
853 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
854 UINT16 OptionNumber;
855
856 if ((VariableName == NULL) || (Option == NULL)) {
857 return EFI_INVALID_PARAMETER;
858 }
859
860 if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
861 return EFI_INVALID_PARAMETER;
862 }
863
864 //
865 // Read the variable
866 //
867 GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
868 if (Variable == NULL) {
869 return EFI_NOT_FOUND;
870 }
871
872 //
873 // Validate *#### variable data.
874 //
875 if (!BmValidateOption(Variable, VariableSize)) {
876 FreePool (Variable);
877 return EFI_INVALID_PARAMETER;
878 }
879
880 //
881 // Get the option attribute
882 //
883 VariablePtr = Variable;
884 Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
885 VariablePtr += sizeof (UINT32);
886
887 //
888 // Get the option's device path size
889 //
890 FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
891 VariablePtr += sizeof (UINT16);
892
893 //
894 // Get the option's description string
895 //
896 Description = (CHAR16 *) VariablePtr;
897
898 //
899 // Get the option's description string size
900 //
901 VariablePtr += StrSize ((CHAR16 *) VariablePtr);
902
903 //
904 // Get the option's device path
905 //
906 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
907 VariablePtr += FilePathSize;
908
909 OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
910 if (OptionalDataSize == 0) {
911 OptionalData = NULL;
912 } else {
913 OptionalData = VariablePtr;
914 }
915
916 Status = EfiBootManagerInitializeLoadOption (
917 Option,
918 OptionNumber,
919 OptionType,
920 Attribute,
921 Description,
922 FilePath,
923 OptionalData,
924 OptionalDataSize
925 );
926 ASSERT_EFI_ERROR (Status);
927
928 CopyGuid (&Option->VendorGuid, VendorGuid);
929
930 FreePool (Variable);
931 return Status;
932 }
933
934 /**
935 Build the Boot#### or Driver#### option from the VariableName.
936
937 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
938 @param Option Return the Boot#### or Driver#### option.
939
940 @retval EFI_SUCCESS Get the option just been created
941 @retval EFI_NOT_FOUND Failed to get the new option
942 **/
943 EFI_STATUS
944 EFIAPI
945 EfiBootManagerVariableToLoadOption (
946 IN CHAR16 *VariableName,
947 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
948 )
949 {
950 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
951 }
952
953 typedef struct {
954 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
955 EFI_GUID *Guid;
956 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
957 UINTN OptionCount;
958 } BM_COLLECT_LOAD_OPTIONS_PARAM;
959
960 /**
961 Visitor function to collect the Platform Recovery load options or OS Recovery
962 load options from NV storage.
963
964 @param Name Variable name.
965 @param Guid Variable GUID.
966 @param Context The same context passed to BmForEachVariable.
967 **/
968 VOID
969 BmCollectLoadOptions (
970 IN CHAR16 *Name,
971 IN EFI_GUID *Guid,
972 IN VOID *Context
973 )
974 {
975 EFI_STATUS Status;
976 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
977 UINT16 OptionNumber;
978 EFI_BOOT_MANAGER_LOAD_OPTION Option;
979 UINTN Index;
980 BM_COLLECT_LOAD_OPTIONS_PARAM *Param;
981
982 Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
983
984 if (CompareGuid (Guid, Param->Guid) && (
985 Param->OptionType == LoadOptionTypePlatformRecovery &&
986 BmIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
987 OptionType == LoadOptionTypePlatformRecovery
988 )) {
989 Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
990 if (!EFI_ERROR (Status)) {
991 for (Index = 0; Index < Param->OptionCount; Index++) {
992 if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
993 break;
994 }
995 }
996 Param->Options = ReallocatePool (
997 Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
998 (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
999 Param->Options
1000 );
1001 ASSERT (Param->Options != NULL);
1002 CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1003 CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1004 Param->OptionCount++;
1005 }
1006 }
1007 }
1008
1009 /**
1010 Returns an array of load options based on the EFI variable
1011 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
1012 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
1013
1014 @param LoadOptionCount Returns number of entries in the array.
1015 @param LoadOptionType The type of the load option.
1016
1017 @retval NULL No load options exist.
1018 @retval !NULL Array of load option entries.
1019
1020 **/
1021 EFI_BOOT_MANAGER_LOAD_OPTION *
1022 EFIAPI
1023 EfiBootManagerGetLoadOptions (
1024 OUT UINTN *OptionCount,
1025 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
1026 )
1027 {
1028 EFI_STATUS Status;
1029 UINT16 *OptionOrder;
1030 UINTN OptionOrderSize;
1031 UINTN Index;
1032 UINTN OptionIndex;
1033 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
1034 CHAR16 OptionName[BM_OPTION_NAME_LEN];
1035 UINT16 OptionNumber;
1036 BM_COLLECT_LOAD_OPTIONS_PARAM Param;
1037
1038 *OptionCount = 0;
1039 Options = NULL;
1040
1041 if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
1042 //
1043 // Read the BootOrder, or DriverOrder variable.
1044 //
1045 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
1046 if (OptionOrder == NULL) {
1047 return NULL;
1048 }
1049
1050 *OptionCount = OptionOrderSize / sizeof (UINT16);
1051
1052 Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1053 ASSERT (Options != NULL);
1054
1055 OptionIndex = 0;
1056 for (Index = 0; Index < *OptionCount; Index++) {
1057 OptionNumber = OptionOrder[Index];
1058 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
1059
1060 Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
1061 if (EFI_ERROR (Status)) {
1062 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
1063 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
1064 } else {
1065 ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
1066 OptionIndex++;
1067 }
1068 }
1069
1070 if (OptionOrder != NULL) {
1071 FreePool (OptionOrder);
1072 }
1073
1074 if (OptionIndex < *OptionCount) {
1075 Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
1076 ASSERT (Options != NULL);
1077 *OptionCount = OptionIndex;
1078 }
1079
1080 } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
1081 Param.OptionType = LoadOptionTypePlatformRecovery;
1082 Param.Options = NULL;
1083 Param.OptionCount = 0;
1084 Param.Guid = &gEfiGlobalVariableGuid;
1085
1086 BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
1087
1088 *OptionCount = Param.OptionCount;
1089 Options = Param.Options;
1090 }
1091
1092 return Options;
1093 }
1094
1095 /**
1096 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1097
1098 @param LoadOption Pointer to boot option to Free.
1099
1100 @return EFI_SUCCESS BootOption was freed
1101 @return EFI_NOT_FOUND BootOption == NULL
1102
1103 **/
1104 EFI_STATUS
1105 EFIAPI
1106 EfiBootManagerFreeLoadOption (
1107 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1108 )
1109 {
1110 if (LoadOption == NULL) {
1111 return EFI_NOT_FOUND;
1112 }
1113
1114 if (LoadOption->Description != NULL) {
1115 FreePool (LoadOption->Description);
1116 }
1117 if (LoadOption->FilePath != NULL) {
1118 FreePool (LoadOption->FilePath);
1119 }
1120 if (LoadOption->OptionalData != NULL) {
1121 FreePool (LoadOption->OptionalData);
1122 }
1123
1124 return EFI_SUCCESS;
1125 }
1126
1127 /**
1128 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1129 EfiBootManagerGetLoadOptions().
1130
1131 @param Option Pointer to boot option array to free.
1132 @param OptionCount Number of array entries in BootOption
1133
1134 @return EFI_SUCCESS BootOption was freed
1135 @return EFI_NOT_FOUND BootOption == NULL
1136
1137 **/
1138 EFI_STATUS
1139 EFIAPI
1140 EfiBootManagerFreeLoadOptions (
1141 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
1142 IN UINTN OptionCount
1143 )
1144 {
1145 UINTN Index;
1146
1147 if (Option == NULL) {
1148 return EFI_NOT_FOUND;
1149 }
1150
1151 for (Index = 0;Index < OptionCount; Index++) {
1152 EfiBootManagerFreeLoadOption (&Option[Index]);
1153 }
1154
1155 FreePool (Option);
1156
1157 return EFI_SUCCESS;
1158 }
1159
1160 /**
1161 Return whether the PE header of the load option is valid or not.
1162
1163 @param[in] Type The load option type.
1164 @param[in] FileBuffer The PE file buffer of the load option.
1165 @param[in] FileSize The size of the load option file.
1166
1167 @retval TRUE The PE header of the load option is valid.
1168 @retval FALSE The PE header of the load option is not valid.
1169 **/
1170 BOOLEAN
1171 BmIsLoadOptionPeHeaderValid (
1172 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
1173 IN VOID *FileBuffer,
1174 IN UINTN FileSize
1175 )
1176 {
1177 EFI_IMAGE_DOS_HEADER *DosHeader;
1178 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;
1179 EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;
1180 UINT16 Subsystem;
1181
1182 if (FileBuffer == NULL || FileSize == 0) {
1183 return FALSE;
1184 }
1185
1186 //
1187 // Read dos header
1188 //
1189 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
1190 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
1191 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
1192 ) {
1193 //
1194 // Read and check PE signature
1195 //
1196 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
1197 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
1198 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
1199 ) {
1200 //
1201 // Check PE32 or PE32+ magic, and machine type
1202 //
1203 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
1204 if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
1205 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
1206 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
1207 ) {
1208 //
1209 // Check the Subsystem:
1210 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1211 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1212 //
1213 Subsystem = OptionalHeader->Subsystem;
1214 if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
1215 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
1216 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1217 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1218 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
1219 ) {
1220 return TRUE;
1221 }
1222 }
1223 }
1224 }
1225
1226 return FALSE;
1227 }
1228
1229 /**
1230 Process (load and execute) the load option.
1231
1232 @param LoadOption Pointer to the load option.
1233
1234 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1235 or the load option file path doesn't point to a valid file.
1236 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1237 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1238 **/
1239 EFI_STATUS
1240 EFIAPI
1241 EfiBootManagerProcessLoadOption (
1242 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1243 )
1244 {
1245 EFI_STATUS Status;
1246 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1247 EFI_HANDLE ImageHandle;
1248 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1249 VOID *FileBuffer;
1250 UINTN FileSize;
1251
1252 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
1253 return EFI_INVALID_PARAMETER;
1254 }
1255
1256 if (LoadOption->OptionType == LoadOptionTypeBoot) {
1257 return EFI_UNSUPPORTED;
1258 }
1259
1260 //
1261 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1262 // the boot manager will not automatically load the option.
1263 //
1264 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
1265 return EFI_SUCCESS;
1266 }
1267
1268 Status = EFI_INVALID_PARAMETER;
1269
1270 //
1271 // Load and start the load option.
1272 //
1273 DEBUG ((
1274 DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
1275 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
1276 ));
1277 ImageHandle = NULL;
1278 FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
1279 DEBUG_CODE (
1280 if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
1281 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
1282 BmPrintDp (LoadOption->FilePath);
1283 DEBUG ((EFI_D_INFO, " -> "));
1284 BmPrintDp (FilePath);
1285 DEBUG ((EFI_D_INFO, "\n"));
1286 }
1287 );
1288 if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
1289 Status = gBS->LoadImage (
1290 FALSE,
1291 gImageHandle,
1292 FilePath,
1293 FileBuffer,
1294 FileSize,
1295 &ImageHandle
1296 );
1297 }
1298 if (FilePath != NULL) {
1299 FreePool (FilePath);
1300 }
1301 if (FileBuffer != NULL) {
1302 FreePool (FileBuffer);
1303 }
1304
1305 if (!EFI_ERROR (Status)) {
1306 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1307 ASSERT_EFI_ERROR (Status);
1308
1309 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
1310 ImageInfo->LoadOptions = LoadOption->OptionalData;
1311 //
1312 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1313 //
1314 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
1315
1316 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
1317 DEBUG ((
1318 DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
1319 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
1320 ));
1321
1322 //
1323 // Clear the Watchdog Timer after the image returns
1324 //
1325 gBS->SetWatchdogTimer (0, 0, 0, NULL);
1326 }
1327
1328 return Status;
1329 }