1/** @file
2  Load option library functions which relate with creating and processing load options.
3
4Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include "InternalBm.h"
17
18GLOBAL_REMOVE_IF_UNREFERENCED
19  CHAR16 *mBmLoadOptionName[] = {
20    L"Driver",
21    L"SysPrep",
22    L"Boot",
23    L"PlatformRecovery"
24  };
25
26GLOBAL_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**/
40VOID
41BmForEachVariable (
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**/
87EFI_STATUS
88BmGetFreeOptionNumber (
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**/
167EFI_STATUS
168EFIAPI
169EfiBootManagerLoadOptionToVariable (
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[];
205TODO: FilePathList[] IS:
206A packed array of UEFI device paths.  The first element of the
207array is a device path that describes the device and location of the
208Image for this load option.  The FilePathList[0] is specific
209to the device type.  Other device paths may optionally exist in the
210FilePathList, but their usage is OSV specific. Each element
211in the array is variable length, and ends at the device path end
212structure.
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**/
274EFI_STATUS
275BmAddOptionNumberToOrderVariable (
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**/
344EFI_STATUS
345EFIAPI
346EfiBootManagerAddLoadOptionVariable (
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**/
404VOID
405EFIAPI
406EfiBootManagerSortLoadOptionVariable (
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**/
469EFI_STATUS
470EFIAPI
471EfiBootManagerInitializeLoadOption (
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**/
523INTN
524EFIAPI
525EfiBootManagerFindLoadOption (
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**/
558EFI_STATUS
559EFIAPI
560EfiBootManagerDeleteLoadOptionVariable (
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**/
630UINTN
631BmGetDevicePathSizeEx (
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**/
684UINTN
685BmStrSizeEx (
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**/
715BOOLEAN
716BmValidateOption (
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**/
777BOOLEAN
778BmIsValidLoadOptionVariableName (
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**/
831EFI_STATUS
832EFIAPI
833EfiBootManagerVariableToLoadOptionEx (
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/**
931Build 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**/
939EFI_STATUS
940EFIAPI
941EfiBootManagerVariableToLoadOption (
942  IN  CHAR16                          *VariableName,
943  IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
944  )
945{
946  return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
947}
948
949typedef 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**/
964VOID
965BmCollectLoadOptions (
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**/
1017EFI_BOOT_MANAGER_LOAD_OPTION *
1018EFIAPI
1019EfiBootManagerGetLoadOptions (
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**/
1100EFI_STATUS
1101EFIAPI
1102EfiBootManagerFreeLoadOption (
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**/
1134EFI_STATUS
1135EFIAPI
1136EfiBootManagerFreeLoadOptions (
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**/
1166BOOLEAN
1167BmIsLoadOptionPeHeaderValid (
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**/
1235EFI_STATUS
1236EFIAPI
1237EfiBootManagerProcessLoadOption (
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}
1326