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