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