]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg: PciHostBridgeDxe: don't assume extended config space
[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 - 2016, 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 UINTN Index;
568 CHAR16 OptionName[BM_OPTION_NAME_LEN];
569
570 if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
571 return EFI_INVALID_PARAMETER;
572 }
573
574 if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
575 //
576 // If the associated *Order exists, firstly remove the reference in *Order for
577 // Driver####, SysPrep#### and Boot####.
578 //
579 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);
580 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));
581
582 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
583 if (OptionOrder[Index] == OptionNumber) {
584 OptionOrderSize -= sizeof (UINT16);
585 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
586 gRT->SetVariable (
587 mBmLoadOptionOrderName[OptionType],
588 &gEfiGlobalVariableGuid,
589 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
590 OptionOrderSize,
591 OptionOrder
592 );
593 break;
594 }
595 }
596 if (OptionOrder != NULL) {
597 FreePool (OptionOrder);
598 }
599 }
600
601 //
602 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.
603 //
604 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);
605 return gRT->SetVariable (
606 OptionName,
607 &gEfiGlobalVariableGuid,
608 0,
609 0,
610 NULL
611 );
612 }
613
614 /**
615 Returns the size of a device path in bytes.
616
617 This function returns the size, in bytes, of the device path data structure
618 specified by DevicePath including the end of device path node. If DevicePath
619 is NULL, then 0 is returned. If the length of the device path is bigger than
620 MaxSize, also return 0 to indicate this is an invalidate device path.
621
622 @param DevicePath A pointer to a device path data structure.
623 @param MaxSize Max valid device path size. If big than this size,
624 return error.
625
626 @retval 0 An invalid device path.
627 @retval Others The size of a device path in bytes.
628
629 **/
630 UINTN
631 BmGetDevicePathSizeEx (
632 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
633 IN UINTN MaxSize
634 )
635 {
636 UINTN Size;
637 UINTN NodeSize;
638
639 if (DevicePath == NULL) {
640 return 0;
641 }
642
643 //
644 // Search for the end of the device path structure
645 //
646 Size = 0;
647 while (!IsDevicePathEnd (DevicePath)) {
648 NodeSize = DevicePathNodeLength (DevicePath);
649 if (NodeSize == 0) {
650 return 0;
651 }
652 Size += NodeSize;
653 if (Size > MaxSize) {
654 return 0;
655 }
656 DevicePath = NextDevicePathNode (DevicePath);
657 }
658 Size += DevicePathNodeLength (DevicePath);
659 if (Size > MaxSize) {
660 return 0;
661 }
662
663 return Size;
664 }
665
666 /**
667 Returns the length of a Null-terminated Unicode string. If the length is
668 bigger than MaxStringLen, return length 0 to indicate that this is an
669 invalidate string.
670
671 This function returns the number of Unicode characters in the Null-terminated
672 Unicode string specified by String.
673
674 If String is NULL, then ASSERT().
675 If String is not aligned on a 16-bit boundary, then ASSERT().
676
677 @param String A pointer to a Null-terminated Unicode string.
678 @param MaxStringLen Max string len in this string.
679
680 @retval 0 An invalid string.
681 @retval Others The length of String.
682
683 **/
684 UINTN
685 BmStrSizeEx (
686 IN CONST CHAR16 *String,
687 IN UINTN MaxStringLen
688 )
689 {
690 UINTN Length;
691
692 ASSERT (String != NULL && MaxStringLen != 0);
693 ASSERT (((UINTN) String & BIT0) == 0);
694
695 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
696
697 if (*String != L'\0' && MaxStringLen == Length) {
698 return 0;
699 }
700
701 return Length + 2;
702 }
703
704 /**
705 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####
706 variable (VendorGuid/Name)
707
708 @param Variable The variable data.
709 @param VariableSize The variable size.
710
711 @retval TRUE The variable data is correct.
712 @retval FALSE The variable data is corrupted.
713
714 **/
715 BOOLEAN
716 BmValidateOption (
717 UINT8 *Variable,
718 UINTN VariableSize
719 )
720 {
721 UINT16 FilePathSize;
722 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
723 UINTN DescriptionSize;
724
725 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
726 return FALSE;
727 }
728
729 //
730 // Skip the option attribute
731 //
732 Variable += sizeof (UINT32);
733
734 //
735 // Get the option's device path size
736 //
737 FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
738 Variable += sizeof (UINT16);
739
740 //
741 // Get the option's description string size
742 //
743 DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
744 Variable += DescriptionSize;
745
746 //
747 // Get the option's device path
748 //
749 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
750
751 //
752 // Validation boot option variable.
753 //
754 if ((FilePathSize == 0) || (DescriptionSize == 0)) {
755 return FALSE;
756 }
757
758 if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
759 return FALSE;
760 }
761
762 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
763 }
764
765 /**
766 Check whether the VariableName is a valid load option variable name
767 and return the load option type and option number.
768
769 @param VariableName The name of the load option variable.
770 @param OptionType Return the load option type.
771 @param OptionNumber Return the load option number.
772
773 @retval TRUE The variable name is valid; The load option type and
774 load option number is returned.
775 @retval FALSE The variable name is NOT valid.
776 **/
777 BOOLEAN
778 BmIsValidLoadOptionVariableName (
779 IN CHAR16 *VariableName,
780 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
781 OUT UINT16 *OptionNumber
782 )
783 {
784 UINTN VariableNameLen;
785 UINTN Index;
786 UINTN Uint;
787
788 VariableNameLen = StrLen (VariableName);
789
790 if (VariableNameLen <= 4) {
791 return FALSE;
792 }
793
794 for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
795 if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
796 (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
797 ) {
798 break;
799 }
800 }
801
802 if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
803 return FALSE;
804 }
805
806 *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
807 *OptionNumber = 0;
808 for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
809 Uint = BmCharToUint (VariableName[Index]);
810 if (Uint == -1) {
811 break;
812 } else {
813 *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
814 }
815 }
816
817 return (BOOLEAN) (Index == VariableNameLen);
818 }
819
820 /**
821 Build the Boot#### or Driver#### option from the VariableName.
822
823 @param VariableName Variable name of the load option
824 @param VendorGuid Variable GUID of the load option
825 @param Option Return the load option.
826
827 @retval EFI_SUCCESS Get the option just been created
828 @retval EFI_NOT_FOUND Failed to get the new option
829
830 **/
831 EFI_STATUS
832 EFIAPI
833 EfiBootManagerVariableToLoadOptionEx (
834 IN CHAR16 *VariableName,
835 IN EFI_GUID *VendorGuid,
836 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
837 )
838 {
839 EFI_STATUS Status;
840 UINT32 Attribute;
841 UINT16 FilePathSize;
842 UINT8 *Variable;
843 UINT8 *VariablePtr;
844 UINTN VariableSize;
845 EFI_DEVICE_PATH_PROTOCOL *FilePath;
846 UINT8 *OptionalData;
847 UINT32 OptionalDataSize;
848 CHAR16 *Description;
849 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
850 UINT16 OptionNumber;
851
852 if ((VariableName == NULL) || (Option == NULL)) {
853 return EFI_INVALID_PARAMETER;
854 }
855
856 if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
857 return EFI_INVALID_PARAMETER;
858 }
859
860 //
861 // Read the variable
862 //
863 GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
864 if (Variable == NULL) {
865 return EFI_NOT_FOUND;
866 }
867
868 //
869 // Validate *#### variable data.
870 //
871 if (!BmValidateOption(Variable, VariableSize)) {
872 FreePool (Variable);
873 return EFI_INVALID_PARAMETER;
874 }
875
876 //
877 // Get the option attribute
878 //
879 VariablePtr = Variable;
880 Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
881 VariablePtr += sizeof (UINT32);
882
883 //
884 // Get the option's device path size
885 //
886 FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
887 VariablePtr += sizeof (UINT16);
888
889 //
890 // Get the option's description string
891 //
892 Description = (CHAR16 *) VariablePtr;
893
894 //
895 // Get the option's description string size
896 //
897 VariablePtr += StrSize ((CHAR16 *) VariablePtr);
898
899 //
900 // Get the option's device path
901 //
902 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
903 VariablePtr += FilePathSize;
904
905 OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
906 if (OptionalDataSize == 0) {
907 OptionalData = NULL;
908 } else {
909 OptionalData = VariablePtr;
910 }
911
912 Status = EfiBootManagerInitializeLoadOption (
913 Option,
914 OptionNumber,
915 OptionType,
916 Attribute,
917 Description,
918 FilePath,
919 OptionalData,
920 OptionalDataSize
921 );
922 ASSERT_EFI_ERROR (Status);
923
924 CopyGuid (&Option->VendorGuid, VendorGuid);
925
926 FreePool (Variable);
927 return Status;
928 }
929
930 /**
931 Build the Boot#### or Driver#### option from the VariableName.
932
933 @param VariableName EFI Variable name indicate if it is Boot#### or Driver####
934 @param Option Return the Boot#### or Driver#### option.
935
936 @retval EFI_SUCCESS Get the option just been created
937 @retval EFI_NOT_FOUND Failed to get the new option
938 **/
939 EFI_STATUS
940 EFIAPI
941 EfiBootManagerVariableToLoadOption (
942 IN CHAR16 *VariableName,
943 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
944 )
945 {
946 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
947 }
948
949 typedef struct {
950 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
951 EFI_GUID *Guid;
952 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
953 UINTN OptionCount;
954 } BM_COLLECT_LOAD_OPTIONS_PARAM;
955
956 /**
957 Visitor function to collect the Platform Recovery load options or OS Recovery
958 load options from NV storage.
959
960 @param Name Variable name.
961 @param Guid Variable GUID.
962 @param Context The same context passed to BmForEachVariable.
963 **/
964 VOID
965 BmCollectLoadOptions (
966 IN CHAR16 *Name,
967 IN EFI_GUID *Guid,
968 IN VOID *Context
969 )
970 {
971 EFI_STATUS Status;
972 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
973 UINT16 OptionNumber;
974 EFI_BOOT_MANAGER_LOAD_OPTION Option;
975 UINTN Index;
976 BM_COLLECT_LOAD_OPTIONS_PARAM *Param;
977
978 Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;
979
980 if (CompareGuid (Guid, Param->Guid) && (
981 Param->OptionType == LoadOptionTypePlatformRecovery &&
982 BmIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&
983 OptionType == LoadOptionTypePlatformRecovery
984 )) {
985 Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);
986 if (!EFI_ERROR (Status)) {
987 for (Index = 0; Index < Param->OptionCount; Index++) {
988 if (Param->Options[Index].OptionNumber > Option.OptionNumber) {
989 break;
990 }
991 }
992 Param->Options = ReallocatePool (
993 Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
994 (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
995 Param->Options
996 );
997 ASSERT (Param->Options != NULL);
998 CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
999 CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1000 Param->OptionCount++;
1001 }
1002 }
1003 }
1004
1005 /**
1006 Returns an array of load options based on the EFI variable
1007 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
1008 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
1009
1010 @param LoadOptionCount Returns number of entries in the array.
1011 @param LoadOptionType The type of the load option.
1012
1013 @retval NULL No load options exist.
1014 @retval !NULL Array of load option entries.
1015
1016 **/
1017 EFI_BOOT_MANAGER_LOAD_OPTION *
1018 EFIAPI
1019 EfiBootManagerGetLoadOptions (
1020 OUT UINTN *OptionCount,
1021 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
1022 )
1023 {
1024 EFI_STATUS Status;
1025 UINT16 *OptionOrder;
1026 UINTN OptionOrderSize;
1027 UINTN Index;
1028 UINTN OptionIndex;
1029 EFI_BOOT_MANAGER_LOAD_OPTION *Options;
1030 CHAR16 OptionName[BM_OPTION_NAME_LEN];
1031 UINT16 OptionNumber;
1032 BM_COLLECT_LOAD_OPTIONS_PARAM Param;
1033
1034 *OptionCount = 0;
1035 Options = NULL;
1036
1037 if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
1038 //
1039 // Read the BootOrder, or DriverOrder variable.
1040 //
1041 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
1042 if (OptionOrder == NULL) {
1043 return NULL;
1044 }
1045
1046 *OptionCount = OptionOrderSize / sizeof (UINT16);
1047
1048 Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
1049 ASSERT (Options != NULL);
1050
1051 OptionIndex = 0;
1052 for (Index = 0; Index < *OptionCount; Index++) {
1053 OptionNumber = OptionOrder[Index];
1054 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
1055
1056 Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
1057 if (EFI_ERROR (Status)) {
1058 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
1059 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
1060 } else {
1061 ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
1062 OptionIndex++;
1063 }
1064 }
1065
1066 if (OptionOrder != NULL) {
1067 FreePool (OptionOrder);
1068 }
1069
1070 if (OptionIndex < *OptionCount) {
1071 Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
1072 ASSERT (Options != NULL);
1073 *OptionCount = OptionIndex;
1074 }
1075
1076 } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {
1077 Param.OptionType = LoadOptionTypePlatformRecovery;
1078 Param.Options = NULL;
1079 Param.OptionCount = 0;
1080 Param.Guid = &gEfiGlobalVariableGuid;
1081
1082 BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);
1083
1084 *OptionCount = Param.OptionCount;
1085 Options = Param.Options;
1086 }
1087
1088 return Options;
1089 }
1090
1091 /**
1092 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
1093
1094 @param LoadOption Pointer to boot option to Free.
1095
1096 @return EFI_SUCCESS BootOption was freed
1097 @return EFI_NOT_FOUND BootOption == NULL
1098
1099 **/
1100 EFI_STATUS
1101 EFIAPI
1102 EfiBootManagerFreeLoadOption (
1103 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1104 )
1105 {
1106 if (LoadOption == NULL) {
1107 return EFI_NOT_FOUND;
1108 }
1109
1110 if (LoadOption->Description != NULL) {
1111 FreePool (LoadOption->Description);
1112 }
1113 if (LoadOption->FilePath != NULL) {
1114 FreePool (LoadOption->FilePath);
1115 }
1116 if (LoadOption->OptionalData != NULL) {
1117 FreePool (LoadOption->OptionalData);
1118 }
1119
1120 return EFI_SUCCESS;
1121 }
1122
1123 /**
1124 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
1125 EfiBootManagerGetLoadOptions().
1126
1127 @param Option Pointer to boot option array to free.
1128 @param OptionCount Number of array entries in BootOption
1129
1130 @return EFI_SUCCESS BootOption was freed
1131 @return EFI_NOT_FOUND BootOption == NULL
1132
1133 **/
1134 EFI_STATUS
1135 EFIAPI
1136 EfiBootManagerFreeLoadOptions (
1137 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
1138 IN UINTN OptionCount
1139 )
1140 {
1141 UINTN Index;
1142
1143 if (Option == NULL) {
1144 return EFI_NOT_FOUND;
1145 }
1146
1147 for (Index = 0;Index < OptionCount; Index++) {
1148 EfiBootManagerFreeLoadOption (&Option[Index]);
1149 }
1150
1151 FreePool (Option);
1152
1153 return EFI_SUCCESS;
1154 }
1155
1156 /**
1157 Return whether the PE header of the load option is valid or not.
1158
1159 @param[in] Type The load option type.
1160 @param[in] FileBuffer The PE file buffer of the load option.
1161 @param[in] FileSize The size of the load option file.
1162
1163 @retval TRUE The PE header of the load option is valid.
1164 @retval FALSE The PE header of the load option is not valid.
1165 **/
1166 BOOLEAN
1167 BmIsLoadOptionPeHeaderValid (
1168 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
1169 IN VOID *FileBuffer,
1170 IN UINTN FileSize
1171 )
1172 {
1173 EFI_IMAGE_DOS_HEADER *DosHeader;
1174 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;
1175 EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;
1176 UINT16 Subsystem;
1177
1178 if (FileBuffer == NULL || FileSize == 0) {
1179 return FALSE;
1180 }
1181
1182 //
1183 // Read dos header
1184 //
1185 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
1186 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
1187 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
1188 ) {
1189 //
1190 // Read and check PE signature
1191 //
1192 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
1193 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
1194 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
1195 ) {
1196 //
1197 // Check PE32 or PE32+ magic, and machine type
1198 //
1199 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
1200 if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
1201 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
1202 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
1203 ) {
1204 //
1205 // Check the Subsystem:
1206 // Driver#### must be of type BootServiceDriver or RuntimeDriver
1207 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
1208 //
1209 Subsystem = OptionalHeader->Subsystem;
1210 if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
1211 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
1212 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1213 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
1214 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
1215 ) {
1216 return TRUE;
1217 }
1218 }
1219 }
1220 }
1221
1222 return FALSE;
1223 }
1224
1225 /**
1226 Process (load and execute) the load option.
1227
1228 @param LoadOption Pointer to the load option.
1229
1230 @retval EFI_INVALID_PARAMETER The load option type is invalid,
1231 or the load option file path doesn't point to a valid file.
1232 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
1233 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
1234 **/
1235 EFI_STATUS
1236 EFIAPI
1237 EfiBootManagerProcessLoadOption (
1238 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
1239 )
1240 {
1241 EFI_STATUS Status;
1242 EFI_DEVICE_PATH_PROTOCOL *FilePath;
1243 EFI_HANDLE ImageHandle;
1244 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
1245 VOID *FileBuffer;
1246 UINTN FileSize;
1247
1248 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
1249 return EFI_INVALID_PARAMETER;
1250 }
1251
1252 if (LoadOption->OptionType == LoadOptionTypeBoot) {
1253 return EFI_UNSUPPORTED;
1254 }
1255
1256 //
1257 // If a load option is not marked as LOAD_OPTION_ACTIVE,
1258 // the boot manager will not automatically load the option.
1259 //
1260 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
1261 return EFI_SUCCESS;
1262 }
1263
1264 Status = EFI_INVALID_PARAMETER;
1265
1266 //
1267 // Load and start the load option.
1268 //
1269 DEBUG ((
1270 DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
1271 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
1272 ));
1273 ImageHandle = NULL;
1274 FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
1275 DEBUG_CODE (
1276 if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
1277 DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
1278 BmPrintDp (LoadOption->FilePath);
1279 DEBUG ((EFI_D_INFO, " -> "));
1280 BmPrintDp (FilePath);
1281 DEBUG ((EFI_D_INFO, "\n"));
1282 }
1283 );
1284 if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
1285 Status = gBS->LoadImage (
1286 FALSE,
1287 gImageHandle,
1288 FilePath,
1289 FileBuffer,
1290 FileSize,
1291 &ImageHandle
1292 );
1293 }
1294 if (FilePath != NULL) {
1295 FreePool (FilePath);
1296 }
1297 if (FileBuffer != NULL) {
1298 FreePool (FileBuffer);
1299 }
1300
1301 if (!EFI_ERROR (Status)) {
1302 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
1303 ASSERT_EFI_ERROR (Status);
1304
1305 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
1306 ImageInfo->LoadOptions = LoadOption->OptionalData;
1307 //
1308 // Before calling the image, enable the Watchdog Timer for the 5-minute period
1309 //
1310 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
1311
1312 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
1313 DEBUG ((
1314 DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
1315 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
1316 ));
1317
1318 //
1319 // Clear the Watchdog Timer after the image returns
1320 //
1321 gBS->SetWatchdogTimer (0, 0, 0, NULL);
1322 }
1323
1324 return Status;
1325 }