]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
d1102dba 4Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
4d76bbcc 5(C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
067ed98a
RN
7\r
8**/\r
9\r
10#include "InternalBm.h"\r
11\r
12GLOBAL_REMOVE_IF_UNREFERENCED\r
13 CHAR16 *mBmLoadOptionName[] = {\r
14 L"Driver",\r
15 L"SysPrep",\r
780e05ca
RN
16 L"Boot",\r
17 L"PlatformRecovery"\r
067ed98a
RN
18 };\r
19\r
20GLOBAL_REMOVE_IF_UNREFERENCED\r
21 CHAR16 *mBmLoadOptionOrderName[] = {\r
22 EFI_DRIVER_ORDER_VARIABLE_NAME,\r
23 EFI_SYS_PREP_ORDER_VARIABLE_NAME,\r
780e05ca
RN
24 EFI_BOOT_ORDER_VARIABLE_NAME,\r
25 NULL // PlatformRecovery#### doesn't have associated *Order variable\r
067ed98a
RN
26 };\r
27\r
28/**\r
29 Call Visitor function for each variable in variable storage.\r
30\r
31 @param Visitor Visitor function.\r
32 @param Context The context passed to Visitor function.\r
33**/\r
34VOID\r
35BmForEachVariable (\r
d95ff8e8 36 BM_VARIABLE_VISITOR Visitor,\r
067ed98a
RN
37 VOID *Context\r
38 )\r
39{\r
40 EFI_STATUS Status;\r
41 CHAR16 *Name;\r
42 EFI_GUID Guid;\r
43 UINTN NameSize;\r
44 UINTN NewNameSize;\r
45\r
46 NameSize = sizeof (CHAR16);\r
47 Name = AllocateZeroPool (NameSize);\r
48 ASSERT (Name != NULL);\r
49 while (TRUE) {\r
50 NewNameSize = NameSize;\r
51 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
52 if (Status == EFI_BUFFER_TOO_SMALL) {\r
53 Name = ReallocatePool (NameSize, NewNameSize, Name);\r
54 ASSERT (Name != NULL);\r
55 Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);\r
56 NameSize = NewNameSize;\r
57 }\r
58\r
59 if (Status == EFI_NOT_FOUND) {\r
60 break;\r
61 }\r
62 ASSERT_EFI_ERROR (Status);\r
63\r
64 Visitor (Name, &Guid, Context);\r
65 }\r
66\r
67 FreePool (Name);\r
68}\r
69\r
70/**\r
71 Get the Option Number that wasn't used.\r
72\r
73 @param LoadOptionType The load option type.\r
74 @param FreeOptionNumber Return the minimal free option number.\r
75\r
76 @retval EFI_SUCCESS The option number is found and will be returned.\r
77 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.\r
78 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL\r
79\r
80**/\r
81EFI_STATUS\r
82BmGetFreeOptionNumber (\r
83 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,\r
84 OUT UINT16 *FreeOptionNumber\r
85 )\r
86{\r
d1102dba 87\r
067ed98a
RN
88 UINTN OptionNumber;\r
89 UINTN Index;\r
90 UINT16 *OptionOrder;\r
91 UINTN OptionOrderSize;\r
92 UINT16 *BootNext;\r
93\r
94 ASSERT (FreeOptionNumber != NULL);\r
d1102dba 95 ASSERT (LoadOptionType == LoadOptionTypeDriver ||\r
067ed98a
RN
96 LoadOptionType == LoadOptionTypeBoot ||\r
97 LoadOptionType == LoadOptionTypeSysPrep);\r
98\r
99 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
eef53857
RN
100 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
101\r
067ed98a
RN
102 BootNext = NULL;\r
103 if (LoadOptionType == LoadOptionTypeBoot) {\r
104 GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);\r
105 }\r
106\r
d1102dba 107 for (OptionNumber = 0;\r
067ed98a 108 OptionNumber < OptionOrderSize / sizeof (UINT16)\r
d1102dba 109 + ((BootNext != NULL) ? 1 : 0);\r
067ed98a
RN
110 OptionNumber++\r
111 ) {\r
112 //\r
113 // Search in OptionOrder whether the OptionNumber exists\r
114 //\r
115 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
116 if (OptionNumber == OptionOrder[Index]) {\r
117 break;\r
118 }\r
119 }\r
120\r
121 //\r
d1102dba 122 // We didn't find it in the ****Order array and it doesn't equal to BootNext\r
067ed98a
RN
123 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1\r
124 //\r
d1102dba 125 if ((Index == OptionOrderSize / sizeof (UINT16)) &&\r
067ed98a
RN
126 ((BootNext == NULL) || (OptionNumber != *BootNext))\r
127 ) {\r
128 break;\r
129 }\r
130 }\r
131 if (OptionOrder != NULL) {\r
132 FreePool (OptionOrder);\r
133 }\r
134\r
135 if (BootNext != NULL) {\r
136 FreePool (BootNext);\r
137 }\r
138\r
139 //\r
140 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],\r
141 // OptionNumber equals to 0x10000 which is not valid.\r
142 //\r
143 ASSERT (OptionNumber <= 0x10000);\r
144 if (OptionNumber == 0x10000) {\r
145 return EFI_OUT_OF_RESOURCES;\r
146 } else {\r
147 *FreeOptionNumber = (UINT16) OptionNumber;\r
148 return EFI_SUCCESS;\r
149 }\r
150}\r
151\r
152/**\r
780e05ca
RN
153 Create the Boot####, Driver####, SysPrep####, PlatformRecovery#### variable\r
154 from the load option.\r
155\r
067ed98a
RN
156 @param LoadOption Pointer to the load option.\r
157\r
158 @retval EFI_SUCCESS The variable was created.\r
159 @retval Others Error status returned by RT->SetVariable.\r
160**/\r
161EFI_STATUS\r
162EFIAPI\r
163EfiBootManagerLoadOptionToVariable (\r
164 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
165 )\r
166{\r
780e05ca 167 EFI_STATUS Status;\r
067ed98a
RN
168 UINTN VariableSize;\r
169 UINT8 *Variable;\r
170 UINT8 *Ptr;\r
171 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
172 CHAR16 *Description;\r
173 CHAR16 NullChar;\r
780e05ca 174 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
067ed98a
RN
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
d1102dba
LG
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
067ed98a
RN
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
780e05ca
RN
235 if (Option->OptionType == LoadOptionTypePlatformRecovery) {\r
236 //\r
237 // Lock the PlatformRecovery####\r
238 //\r
239 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
240 if (!EFI_ERROR (Status)) {\r
241 Status = VariableLock->RequestToLock (VariableLock, OptionName, &gEfiGlobalVariableGuid);\r
242 ASSERT_EFI_ERROR (Status);\r
243 }\r
244 VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
245 }\r
067ed98a 246\r
4d76bbcc
TP
247 Status = gRT->SetVariable (\r
248 OptionName,\r
249 &gEfiGlobalVariableGuid,\r
250 VariableAttributes,\r
251 VariableSize,\r
252 Variable\r
253 );\r
254 FreePool (Variable);\r
255\r
256 return Status;\r
067ed98a
RN
257}\r
258\r
259/**\r
260 Update order variable .\r
261\r
262 @param OptionOrderName Order variable name which need to be updated.\r
263 @param OptionNumber Option number for the new option.\r
264 @param Position Position of the new load option to put in the ****Order variable.\r
265\r
266 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.\r
267 @retval EFI_ALREADY_STARTED The option number of Option is being used already.\r
268 @retval EFI_STATUS Return the status of gRT->SetVariable ().\r
269\r
270**/\r
271EFI_STATUS\r
272BmAddOptionNumberToOrderVariable (\r
273 IN CHAR16 *OptionOrderName,\r
274 IN UINT16 OptionNumber,\r
275 IN UINTN Position\r
276 )\r
277{\r
278 EFI_STATUS Status;\r
279 UINTN Index;\r
280 UINT16 *OptionOrder;\r
281 UINT16 *NewOptionOrder;\r
282 UINTN OptionOrderSize;\r
283 //\r
284 // Update the option order variable\r
285 //\r
286 GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);\r
eef53857 287 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
067ed98a
RN
288\r
289 Status = EFI_SUCCESS;\r
290 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
291 if (OptionOrder[Index] == OptionNumber) {\r
292 Status = EFI_ALREADY_STARTED;\r
293 break;\r
294 }\r
295 }\r
296\r
297 if (!EFI_ERROR (Status)) {\r
298 Position = MIN (Position, OptionOrderSize / sizeof (UINT16));\r
299\r
300 NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));\r
301 ASSERT (NewOptionOrder != NULL);\r
302 if (OptionOrderSize != 0) {\r
303 CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));\r
304 CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));\r
305 }\r
306 NewOptionOrder[Position] = OptionNumber;\r
307\r
308 Status = gRT->SetVariable (\r
309 OptionOrderName,\r
310 &gEfiGlobalVariableGuid,\r
311 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
312 OptionOrderSize + sizeof (UINT16),\r
313 NewOptionOrder\r
314 );\r
315 FreePool (NewOptionOrder);\r
316 }\r
317\r
318 if (OptionOrder != NULL) {\r
319 FreePool (OptionOrder);\r
320 }\r
321\r
322 return Status;\r
323}\r
324\r
325/**\r
326 This function will register the new Boot####, Driver#### or SysPrep#### option.\r
327 After the *#### is updated, the *Order will also be updated.\r
328\r
8b5c80e0
RN
329 @param Option Pointer to load option to add. If on input\r
330 Option->OptionNumber is LoadOptionNumberUnassigned,\r
331 then on output Option->OptionNumber is updated to\r
332 the number of the new Boot####,\r
333 Driver#### or SysPrep#### option.\r
067ed98a
RN
334 @param Position Position of the new load option to put in the ****Order variable.\r
335\r
336 @retval EFI_SUCCESS The *#### have been successfully registered.\r
337 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.\r
338 @retval EFI_ALREADY_STARTED The option number of Option is being used already.\r
339 Note: this API only adds new load option, no replacement support.\r
340 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the\r
341 option number specified in the Option is LoadOptionNumberUnassigned.\r
8b5c80e0 342 @return Status codes of gRT->SetVariable ().\r
067ed98a
RN
343\r
344**/\r
345EFI_STATUS\r
346EFIAPI\r
347EfiBootManagerAddLoadOptionVariable (\r
8b5c80e0
RN
348 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
349 IN UINTN Position\r
067ed98a
RN
350 )\r
351{\r
352 EFI_STATUS Status;\r
353 UINT16 OptionNumber;\r
354\r
355 if (Option == NULL) {\r
356 return EFI_INVALID_PARAMETER;\r
357 }\r
358\r
d1102dba 359 if (Option->OptionType != LoadOptionTypeDriver &&\r
067ed98a
RN
360 Option->OptionType != LoadOptionTypeSysPrep &&\r
361 Option->OptionType != LoadOptionTypeBoot\r
362 ) {\r
363 return EFI_INVALID_PARAMETER;\r
364 }\r
365\r
366 //\r
367 // Get the free option number if the option number is unassigned\r
368 //\r
369 if (Option->OptionNumber == LoadOptionNumberUnassigned) {\r
370 Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);\r
371 if (EFI_ERROR (Status)) {\r
372 return Status;\r
373 }\r
374 Option->OptionNumber = OptionNumber;\r
375 }\r
376\r
377 if (Option->OptionNumber >= LoadOptionNumberMax) {\r
378 return EFI_INVALID_PARAMETER;\r
379 }\r
380\r
381 Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);\r
382 if (!EFI_ERROR (Status)) {\r
383 //\r
384 // Save the Boot#### or Driver#### variable\r
385 //\r
386 Status = EfiBootManagerLoadOptionToVariable (Option);\r
387 if (EFI_ERROR (Status)) {\r
388 //\r
389 // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.\r
390 //\r
391 EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);\r
392 }\r
393 }\r
394\r
395 return Status;\r
396}\r
397\r
398/**\r
d1102dba 399 Sort the load option. The DriverOrder or BootOrder will be re-created to\r
067ed98a
RN
400 reflect the new order.\r
401\r
402 @param OptionType Load option type\r
403 @param CompareFunction The comparator\r
404**/\r
405VOID\r
406EFIAPI\r
407EfiBootManagerSortLoadOptionVariable (\r
408 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
409 SORT_COMPARE CompareFunction\r
410 )\r
411{\r
412 EFI_STATUS Status;\r
413 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;\r
414 UINTN LoadOptionCount;\r
415 UINTN Index;\r
416 UINT16 *OptionOrder;\r
417\r
418 LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);\r
419\r
420 //\r
421 // Insertion sort algorithm\r
422 //\r
423 PerformQuickSort (\r
424 LoadOption,\r
425 LoadOptionCount,\r
426 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
427 CompareFunction\r
428 );\r
429\r
430 //\r
431 // Create new ****Order variable\r
432 //\r
433 OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));\r
434 ASSERT (OptionOrder != NULL);\r
435 for (Index = 0; Index < LoadOptionCount; Index++) {\r
436 OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;\r
437 }\r
438\r
439 Status = gRT->SetVariable (\r
440 mBmLoadOptionOrderName[OptionType],\r
441 &gEfiGlobalVariableGuid,\r
442 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
443 LoadOptionCount * sizeof (UINT16),\r
444 OptionOrder\r
445 );\r
446 //\r
447 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.\r
448 //\r
449 ASSERT_EFI_ERROR (Status);\r
450\r
451 FreePool (OptionOrder);\r
452 EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);\r
453}\r
454\r
455/**\r
456 Initialize a load option.\r
457\r
458 @param Option Pointer to the load option to be initialized.\r
459 @param OptionNumber Option number of the load option.\r
460 @param OptionType Type of the load option.\r
461 @param Attributes Attributes of the load option.\r
462 @param Description Description of the load option.\r
463 @param FilePath Device path of the load option.\r
464 @param OptionalData Optional data of the load option.\r
465 @param OptionalDataSize Size of the optional data of the load option.\r
466\r
467 @retval EFI_SUCCESS The load option was initialized successfully.\r
468 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.\r
469**/\r
470EFI_STATUS\r
471EFIAPI\r
472EfiBootManagerInitializeLoadOption (\r
473 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
474 IN UINTN OptionNumber,\r
475 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,\r
476 IN UINT32 Attributes,\r
477 IN CHAR16 *Description,\r
478 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
479 IN UINT8 *OptionalData, OPTIONAL\r
480 IN UINT32 OptionalDataSize\r
481 )\r
482{\r
483 if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {\r
484 return EFI_INVALID_PARAMETER;\r
485 }\r
486\r
487 if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||\r
488 ((OptionalData == NULL) && (OptionalDataSize != 0))) {\r
489 return EFI_INVALID_PARAMETER;\r
490 }\r
491\r
492 if ((UINT32) OptionType >= LoadOptionTypeMax) {\r
493 return EFI_INVALID_PARAMETER;\r
494 }\r
495\r
496 ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
497 Option->OptionNumber = OptionNumber;\r
498 Option->OptionType = OptionType;\r
499 Option->Attributes = Attributes;\r
500 Option->Description = AllocateCopyPool (StrSize (Description), Description);\r
501 Option->FilePath = DuplicateDevicePath (FilePath);\r
502 if (OptionalData != NULL) {\r
503 Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);\r
504 Option->OptionalDataSize = OptionalDataSize;\r
505 }\r
506\r
507 return EFI_SUCCESS;\r
508}\r
509\r
510\r
511/**\r
512 Return the index of the load option in the load option array.\r
513\r
d1102dba 514 The function consider two load options are equal when the\r
067ed98a
RN
515 OptionType, Attributes, Description, FilePath and OptionalData are equal.\r
516\r
517 @param Key Pointer to the load option to be found.\r
518 @param Array Pointer to the array of load options to be found.\r
519 @param Count Number of entries in the Array.\r
520\r
521 @retval -1 Key wasn't found in the Array.\r
522 @retval 0 ~ Count-1 The index of the Key in the Array.\r
523**/\r
524INTN\r
5d3a9896
SW
525EFIAPI\r
526EfiBootManagerFindLoadOption (\r
067ed98a
RN
527 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,\r
528 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,\r
529 IN UINTN Count\r
530 )\r
531{\r
532 UINTN Index;\r
533\r
534 for (Index = 0; Index < Count; Index++) {\r
535 if ((Key->OptionType == Array[Index].OptionType) &&\r
536 (Key->Attributes == Array[Index].Attributes) &&\r
537 (StrCmp (Key->Description, Array[Index].Description) == 0) &&\r
538 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&\r
539 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&\r
540 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {\r
541 return (INTN) Index;\r
542 }\r
543 }\r
544\r
545 return -1;\r
546}\r
547\r
548/**\r
549 Delete the load option.\r
550\r
551 @param OptionNumber Indicate the option number of load option\r
552 @param OptionType Indicate the type of load option\r
553\r
554 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.\r
555 @retval EFI_NOT_FOUND The load option cannot be found\r
556 @retval EFI_SUCCESS The load option was deleted\r
557 @retval others Status of RT->SetVariable()\r
558**/\r
559EFI_STATUS\r
560EFIAPI\r
561EfiBootManagerDeleteLoadOptionVariable (\r
562 IN UINTN OptionNumber,\r
563 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType\r
564 )\r
565{\r
566 UINT16 *OptionOrder;\r
567 UINTN OptionOrderSize;\r
067ed98a 568 UINTN Index;\r
780e05ca 569 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
067ed98a
RN
570\r
571 if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {\r
572 return EFI_INVALID_PARAMETER;\r
573 }\r
574\r
067ed98a
RN
575 if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {\r
576 //\r
2e26862c
RN
577 // If the associated *Order exists, firstly remove the reference in *Order for\r
578 // Driver####, SysPrep#### and Boot####.\r
067ed98a 579 //\r
833a8349 580 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
eef53857
RN
581 ASSERT ((OptionOrder != NULL && OptionOrderSize != 0) || (OptionOrder == NULL && OptionOrderSize == 0));\r
582\r
067ed98a
RN
583 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {\r
584 if (OptionOrder[Index] == OptionNumber) {\r
585 OptionOrderSize -= sizeof (UINT16);\r
586 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));\r
2e26862c
RN
587 gRT->SetVariable (\r
588 mBmLoadOptionOrderName[OptionType],\r
589 &gEfiGlobalVariableGuid,\r
590 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
591 OptionOrderSize,\r
592 OptionOrder\r
593 );\r
067ed98a
RN
594 break;\r
595 }\r
596 }\r
597 if (OptionOrder != NULL) {\r
598 FreePool (OptionOrder);\r
599 }\r
600 }\r
601\r
2e26862c
RN
602 //\r
603 // Remove the Driver####, SysPrep####, Boot#### or PlatformRecovery#### itself.\r
604 //\r
605 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[OptionType], OptionNumber);\r
606 return gRT->SetVariable (\r
607 OptionName,\r
608 &gEfiGlobalVariableGuid,\r
609 0,\r
610 0,\r
611 NULL\r
612 );\r
067ed98a
RN
613}\r
614\r
067ed98a
RN
615/**\r
616 Returns the size of a device path in bytes.\r
617\r
d1102dba
LG
618 This function returns the size, in bytes, of the device path data structure\r
619 specified by DevicePath including the end of device path node. If DevicePath\r
067ed98a
RN
620 is NULL, then 0 is returned. If the length of the device path is bigger than\r
621 MaxSize, also return 0 to indicate this is an invalidate device path.\r
622\r
623 @param DevicePath A pointer to a device path data structure.\r
d1102dba 624 @param MaxSize Max valid device path size. If big than this size,\r
067ed98a 625 return error.\r
d1102dba 626\r
067ed98a
RN
627 @retval 0 An invalid device path.\r
628 @retval Others The size of a device path in bytes.\r
629\r
630**/\r
631UINTN\r
632BmGetDevicePathSizeEx (\r
633 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
634 IN UINTN MaxSize\r
635 )\r
636{\r
637 UINTN Size;\r
638 UINTN NodeSize;\r
639\r
640 if (DevicePath == NULL) {\r
641 return 0;\r
642 }\r
643\r
644 //\r
645 // Search for the end of the device path structure\r
646 //\r
647 Size = 0;\r
648 while (!IsDevicePathEnd (DevicePath)) {\r
649 NodeSize = DevicePathNodeLength (DevicePath);\r
650 if (NodeSize == 0) {\r
651 return 0;\r
652 }\r
653 Size += NodeSize;\r
654 if (Size > MaxSize) {\r
655 return 0;\r
656 }\r
657 DevicePath = NextDevicePathNode (DevicePath);\r
658 }\r
659 Size += DevicePathNodeLength (DevicePath);\r
660 if (Size > MaxSize) {\r
661 return 0;\r
662 }\r
663\r
664 return Size;\r
665}\r
666\r
667/**\r
d1102dba
LG
668 Returns the length of a Null-terminated Unicode string. If the length is\r
669 bigger than MaxStringLen, return length 0 to indicate that this is an\r
067ed98a
RN
670 invalidate string.\r
671\r
672 This function returns the number of Unicode characters in the Null-terminated\r
d1102dba 673 Unicode string specified by String.\r
067ed98a
RN
674\r
675 If String is NULL, then ASSERT().\r
676 If String is not aligned on a 16-bit boundary, then ASSERT().\r
677\r
678 @param String A pointer to a Null-terminated Unicode string.\r
679 @param MaxStringLen Max string len in this string.\r
680\r
681 @retval 0 An invalid string.\r
682 @retval Others The length of String.\r
683\r
684**/\r
685UINTN\r
686BmStrSizeEx (\r
687 IN CONST CHAR16 *String,\r
688 IN UINTN MaxStringLen\r
689 )\r
690{\r
691 UINTN Length;\r
692\r
693 ASSERT (String != NULL && MaxStringLen != 0);\r
694 ASSERT (((UINTN) String & BIT0) == 0);\r
695\r
696 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);\r
697\r
698 if (*String != L'\0' && MaxStringLen == Length) {\r
699 return 0;\r
700 }\r
701\r
702 return Length + 2;\r
703}\r
704\r
705/**\r
780e05ca
RN
706 Validate the Boot####, Driver####, SysPrep#### and PlatformRecovery####\r
707 variable (VendorGuid/Name)\r
067ed98a
RN
708\r
709 @param Variable The variable data.\r
710 @param VariableSize The variable size.\r
711\r
712 @retval TRUE The variable data is correct.\r
713 @retval FALSE The variable data is corrupted.\r
714\r
715**/\r
d1102dba 716BOOLEAN\r
067ed98a
RN
717BmValidateOption (\r
718 UINT8 *Variable,\r
719 UINTN VariableSize\r
720 )\r
721{\r
722 UINT16 FilePathSize;\r
723 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
724 UINTN DescriptionSize;\r
725\r
726 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {\r
727 return FALSE;\r
728 }\r
729\r
730 //\r
731 // Skip the option attribute\r
732 //\r
733 Variable += sizeof (UINT32);\r
734\r
735 //\r
736 // Get the option's device path size\r
737 //\r
738 FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);\r
739 Variable += sizeof (UINT16);\r
740\r
741 //\r
742 // Get the option's description string size\r
743 //\r
744 DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));\r
745 Variable += DescriptionSize;\r
746\r
747 //\r
748 // Get the option's device path\r
749 //\r
750 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;\r
751\r
752 //\r
753 // Validation boot option variable.\r
754 //\r
755 if ((FilePathSize == 0) || (DescriptionSize == 0)) {\r
756 return FALSE;\r
757 }\r
758\r
759 if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {\r
760 return FALSE;\r
761 }\r
762\r
763 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);\r
764}\r
765\r
766/**\r
767 Check whether the VariableName is a valid load option variable name\r
768 and return the load option type and option number.\r
769\r
770 @param VariableName The name of the load option variable.\r
771 @param OptionType Return the load option type.\r
772 @param OptionNumber Return the load option number.\r
773\r
774 @retval TRUE The variable name is valid; The load option type and\r
775 load option number is returned.\r
776 @retval FALSE The variable name is NOT valid.\r
777**/\r
778BOOLEAN\r
3dc5c1ae
TP
779EFIAPI\r
780EfiBootManagerIsValidLoadOptionVariableName (\r
067ed98a 781 IN CHAR16 *VariableName,\r
3dc5c1ae
TP
782 OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType OPTIONAL,\r
783 OUT UINT16 *OptionNumber OPTIONAL\r
067ed98a
RN
784 )\r
785{\r
786 UINTN VariableNameLen;\r
787 UINTN Index;\r
788 UINTN Uint;\r
5e6e2dcc
RN
789 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LocalOptionType;\r
790 UINT16 LocalOptionNumber;\r
067ed98a 791\r
3dc5c1ae
TP
792 if (VariableName == NULL) {\r
793 return FALSE;\r
794 }\r
795\r
067ed98a
RN
796 VariableNameLen = StrLen (VariableName);\r
797\r
5e6e2dcc
RN
798 //\r
799 // Return FALSE when the variable name length is too small.\r
800 //\r
067ed98a
RN
801 if (VariableNameLen <= 4) {\r
802 return FALSE;\r
803 }\r
804\r
5e6e2dcc
RN
805 //\r
806 // Return FALSE when the variable name doesn't start with Driver/SysPrep/Boot/PlatformRecovery.\r
807 //\r
808 for (LocalOptionType = 0; LocalOptionType < ARRAY_SIZE (mBmLoadOptionName); LocalOptionType++) {\r
809 if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[LocalOptionType])) &&\r
810 (StrnCmp (VariableName, mBmLoadOptionName[LocalOptionType], VariableNameLen - 4) == 0)\r
067ed98a
RN
811 ) {\r
812 break;\r
813 }\r
814 }\r
5e6e2dcc
RN
815 if (LocalOptionType == ARRAY_SIZE (mBmLoadOptionName)) {\r
816 return FALSE;\r
817 }\r
067ed98a 818\r
5e6e2dcc
RN
819 //\r
820 // Return FALSE when the last four characters are not hex digits.\r
821 //\r
822 LocalOptionNumber = 0;\r
823 for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {\r
824 Uint = BmCharToUint (VariableName[Index]);\r
825 if (Uint == -1) {\r
826 break;\r
827 } else {\r
828 LocalOptionNumber = (UINT16) Uint + LocalOptionNumber * 0x10;\r
829 }\r
830 }\r
831 if (Index != VariableNameLen) {\r
067ed98a
RN
832 return FALSE;\r
833 }\r
834\r
3dc5c1ae 835 if (OptionType != NULL) {\r
5e6e2dcc 836 *OptionType = LocalOptionType;\r
3dc5c1ae
TP
837 }\r
838\r
839 if (OptionNumber != NULL) {\r
5e6e2dcc 840 *OptionNumber = LocalOptionNumber;\r
067ed98a
RN
841 }\r
842\r
5e6e2dcc 843 return TRUE;\r
067ed98a
RN
844}\r
845\r
846/**\r
847 Build the Boot#### or Driver#### option from the VariableName.\r
848\r
849 @param VariableName Variable name of the load option\r
850 @param VendorGuid Variable GUID of the load option\r
851 @param Option Return the load option.\r
852\r
853 @retval EFI_SUCCESS Get the option just been created\r
854 @retval EFI_NOT_FOUND Failed to get the new option\r
855\r
856**/\r
857EFI_STATUS\r
858EFIAPI\r
859EfiBootManagerVariableToLoadOptionEx (\r
860 IN CHAR16 *VariableName,\r
861 IN EFI_GUID *VendorGuid,\r
d1102dba 862 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
067ed98a
RN
863 )\r
864{\r
865 EFI_STATUS Status;\r
866 UINT32 Attribute;\r
867 UINT16 FilePathSize;\r
868 UINT8 *Variable;\r
869 UINT8 *VariablePtr;\r
870 UINTN VariableSize;\r
871 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
872 UINT8 *OptionalData;\r
873 UINT32 OptionalDataSize;\r
874 CHAR16 *Description;\r
875 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
876 UINT16 OptionNumber;\r
877\r
878 if ((VariableName == NULL) || (Option == NULL)) {\r
879 return EFI_INVALID_PARAMETER;\r
880 }\r
881\r
3dc5c1ae 882 if (!EfiBootManagerIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {\r
067ed98a
RN
883 return EFI_INVALID_PARAMETER;\r
884 }\r
885\r
886 //\r
887 // Read the variable\r
888 //\r
889 GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);\r
890 if (Variable == NULL) {\r
891 return EFI_NOT_FOUND;\r
892 }\r
893\r
894 //\r
895 // Validate *#### variable data.\r
896 //\r
897 if (!BmValidateOption(Variable, VariableSize)) {\r
898 FreePool (Variable);\r
899 return EFI_INVALID_PARAMETER;\r
900 }\r
901\r
902 //\r
903 // Get the option attribute\r
904 //\r
905 VariablePtr = Variable;\r
906 Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);\r
907 VariablePtr += sizeof (UINT32);\r
908\r
909 //\r
910 // Get the option's device path size\r
911 //\r
912 FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);\r
913 VariablePtr += sizeof (UINT16);\r
914\r
915 //\r
916 // Get the option's description string\r
917 //\r
918 Description = (CHAR16 *) VariablePtr;\r
919\r
920 //\r
921 // Get the option's description string size\r
922 //\r
923 VariablePtr += StrSize ((CHAR16 *) VariablePtr);\r
924\r
925 //\r
926 // Get the option's device path\r
927 //\r
928 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;\r
929 VariablePtr += FilePathSize;\r
930\r
809e2bbf 931 OptionalDataSize = (UINT32) (VariableSize - ((UINTN) VariablePtr - (UINTN) Variable));\r
067ed98a
RN
932 if (OptionalDataSize == 0) {\r
933 OptionalData = NULL;\r
934 } else {\r
935 OptionalData = VariablePtr;\r
936 }\r
937\r
938 Status = EfiBootManagerInitializeLoadOption (\r
939 Option,\r
940 OptionNumber,\r
941 OptionType,\r
942 Attribute,\r
943 Description,\r
944 FilePath,\r
945 OptionalData,\r
946 OptionalDataSize\r
947 );\r
948 ASSERT_EFI_ERROR (Status);\r
949\r
950 CopyGuid (&Option->VendorGuid, VendorGuid);\r
951\r
952 FreePool (Variable);\r
953 return Status;\r
954}\r
955\r
956/**\r
957Build the Boot#### or Driver#### option from the VariableName.\r
958\r
959@param VariableName EFI Variable name indicate if it is Boot#### or Driver####\r
960@param Option Return the Boot#### or Driver#### option.\r
961\r
962@retval EFI_SUCCESS Get the option just been created\r
963@retval EFI_NOT_FOUND Failed to get the new option\r
964**/\r
965EFI_STATUS\r
966EFIAPI\r
967EfiBootManagerVariableToLoadOption (\r
968 IN CHAR16 *VariableName,\r
969 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option\r
970 )\r
971{\r
972 return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);\r
973}\r
974\r
780e05ca
RN
975typedef struct {\r
976 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
977 EFI_GUID *Guid;\r
978 EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
979 UINTN OptionCount;\r
980} BM_COLLECT_LOAD_OPTIONS_PARAM;\r
981\r
982/**\r
983 Visitor function to collect the Platform Recovery load options or OS Recovery\r
984 load options from NV storage.\r
985\r
986 @param Name Variable name.\r
987 @param Guid Variable GUID.\r
988 @param Context The same context passed to BmForEachVariable.\r
989**/\r
990VOID\r
991BmCollectLoadOptions (\r
992 IN CHAR16 *Name,\r
993 IN EFI_GUID *Guid,\r
994 IN VOID *Context\r
995 )\r
996{\r
997 EFI_STATUS Status;\r
998 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;\r
999 UINT16 OptionNumber;\r
1000 EFI_BOOT_MANAGER_LOAD_OPTION Option;\r
1001 UINTN Index;\r
1002 BM_COLLECT_LOAD_OPTIONS_PARAM *Param;\r
1003\r
1004 Param = (BM_COLLECT_LOAD_OPTIONS_PARAM *) Context;\r
1005\r
1006 if (CompareGuid (Guid, Param->Guid) && (\r
1007 Param->OptionType == LoadOptionTypePlatformRecovery &&\r
3dc5c1ae 1008 EfiBootManagerIsValidLoadOptionVariableName (Name, &OptionType, &OptionNumber) &&\r
780e05ca
RN
1009 OptionType == LoadOptionTypePlatformRecovery\r
1010 )) {\r
1011 Status = EfiBootManagerVariableToLoadOptionEx (Name, Guid, &Option);\r
1012 if (!EFI_ERROR (Status)) {\r
1013 for (Index = 0; Index < Param->OptionCount; Index++) {\r
1014 if (Param->Options[Index].OptionNumber > Option.OptionNumber) {\r
1015 break;\r
1016 }\r
1017 }\r
1018 Param->Options = ReallocatePool (\r
1019 Param->OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
1020 (Param->OptionCount + 1) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),\r
1021 Param->Options\r
1022 );\r
1023 ASSERT (Param->Options != NULL);\r
1024 CopyMem (&Param->Options[Index + 1], &Param->Options[Index], (Param->OptionCount - Index) * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
1025 CopyMem (&Param->Options[Index], &Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
1026 Param->OptionCount++;\r
1027 }\r
1028 }\r
1029}\r
1030\r
067ed98a
RN
1031/**\r
1032 Returns an array of load options based on the EFI variable\r
1033 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.\r
d1102dba 1034 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.\r
067ed98a
RN
1035\r
1036 @param LoadOptionCount Returns number of entries in the array.\r
1037 @param LoadOptionType The type of the load option.\r
1038\r
1039 @retval NULL No load options exist.\r
1040 @retval !NULL Array of load option entries.\r
1041\r
1042**/\r
1043EFI_BOOT_MANAGER_LOAD_OPTION *\r
1044EFIAPI\r
1045EfiBootManagerGetLoadOptions (\r
1046 OUT UINTN *OptionCount,\r
1047 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType\r
1048 )\r
1049{\r
780e05ca
RN
1050 EFI_STATUS Status;\r
1051 UINT16 *OptionOrder;\r
1052 UINTN OptionOrderSize;\r
1053 UINTN Index;\r
1054 UINTN OptionIndex;\r
1055 EFI_BOOT_MANAGER_LOAD_OPTION *Options;\r
1056 CHAR16 OptionName[BM_OPTION_NAME_LEN];\r
1057 UINT16 OptionNumber;\r
1058 BM_COLLECT_LOAD_OPTIONS_PARAM Param;\r
067ed98a
RN
1059\r
1060 *OptionCount = 0;\r
780e05ca 1061 Options = NULL;\r
067ed98a
RN
1062\r
1063 if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {\r
1064 //\r
1065 // Read the BootOrder, or DriverOrder variable.\r
1066 //\r
1067 GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);\r
1068 if (OptionOrder == NULL) {\r
1069 return NULL;\r
1070 }\r
1071\r
1072 *OptionCount = OptionOrderSize / sizeof (UINT16);\r
1073\r
1074 Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));\r
1075 ASSERT (Options != NULL);\r
1076\r
1077 OptionIndex = 0;\r
1078 for (Index = 0; Index < *OptionCount; Index++) {\r
1079 OptionNumber = OptionOrder[Index];\r
1080 UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);\r
1081\r
1082 Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);\r
1083 if (EFI_ERROR (Status)) {\r
1084 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));\r
1085 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);\r
1086 } else {\r
1087 ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);\r
1088 OptionIndex++;\r
1089 }\r
1090 }\r
1091\r
1092 if (OptionOrder != NULL) {\r
1093 FreePool (OptionOrder);\r
1094 }\r
1095\r
1096 if (OptionIndex < *OptionCount) {\r
1097 Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);\r
1098 ASSERT (Options != NULL);\r
1099 *OptionCount = OptionIndex;\r
1100 }\r
1101\r
780e05ca
RN
1102 } else if (LoadOptionType == LoadOptionTypePlatformRecovery) {\r
1103 Param.OptionType = LoadOptionTypePlatformRecovery;\r
1104 Param.Options = NULL;\r
1105 Param.OptionCount = 0;\r
1106 Param.Guid = &gEfiGlobalVariableGuid;\r
1107\r
1108 BmForEachVariable (BmCollectLoadOptions, (VOID *) &Param);\r
1109\r
1110 *OptionCount = Param.OptionCount;\r
1111 Options = Param.Options;\r
067ed98a
RN
1112 }\r
1113\r
1114 return Options;\r
1115}\r
1116\r
1117/**\r
1118 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.\r
1119\r
1120 @param LoadOption Pointer to boot option to Free.\r
1121\r
d1102dba
LG
1122 @return EFI_SUCCESS BootOption was freed\r
1123 @return EFI_NOT_FOUND BootOption == NULL\r
067ed98a
RN
1124\r
1125**/\r
1126EFI_STATUS\r
1127EFIAPI\r
1128EfiBootManagerFreeLoadOption (\r
1129 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption\r
1130 )\r
1131{\r
1132 if (LoadOption == NULL) {\r
1133 return EFI_NOT_FOUND;\r
1134 }\r
1135\r
1136 if (LoadOption->Description != NULL) {\r
1137 FreePool (LoadOption->Description);\r
1138 }\r
1139 if (LoadOption->FilePath != NULL) {\r
1140 FreePool (LoadOption->FilePath);\r
1141 }\r
1142 if (LoadOption->OptionalData != NULL) {\r
1143 FreePool (LoadOption->OptionalData);\r
1144 }\r
1145\r
1146 return EFI_SUCCESS;\r
1147}\r
1148\r
1149/**\r
d1102dba 1150 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by\r
067ed98a
RN
1151 EfiBootManagerGetLoadOptions().\r
1152\r
1153 @param Option Pointer to boot option array to free.\r
1154 @param OptionCount Number of array entries in BootOption\r
1155\r
d1102dba
LG
1156 @return EFI_SUCCESS BootOption was freed\r
1157 @return EFI_NOT_FOUND BootOption == NULL\r
067ed98a
RN
1158\r
1159**/\r
1160EFI_STATUS\r
1161EFIAPI\r
1162EfiBootManagerFreeLoadOptions (\r
1163 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,\r
1164 IN UINTN OptionCount\r
1165 )\r
1166{\r
1167 UINTN Index;\r
1168\r
1169 if (Option == NULL) {\r
1170 return EFI_NOT_FOUND;\r
1171 }\r
1172\r
1173 for (Index = 0;Index < OptionCount; Index++) {\r
1174 EfiBootManagerFreeLoadOption (&Option[Index]);\r
1175 }\r
1176\r
1177 FreePool (Option);\r
1178\r
1179 return EFI_SUCCESS;\r
1180}\r
1181\r
1182/**\r
1183 Return whether the PE header of the load option is valid or not.\r
1184\r
1185 @param[in] Type The load option type.\r
08eff917
RN
1186 It's used to check whether the load option is valid.\r
1187 When it's LoadOptionTypeMax, the routine only guarantees\r
1188 the load option is a valid PE image but doesn't guarantee\r
1189 the PE's subsystem type is valid.\r
067ed98a
RN
1190 @param[in] FileBuffer The PE file buffer of the load option.\r
1191 @param[in] FileSize The size of the load option file.\r
1192\r
1193 @retval TRUE The PE header of the load option is valid.\r
1194 @retval FALSE The PE header of the load option is not valid.\r
1195**/\r
1196BOOLEAN\r
1197BmIsLoadOptionPeHeaderValid (\r
1198 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
1199 IN VOID *FileBuffer,\r
1200 IN UINTN FileSize\r
1201 )\r
1202{\r
1203 EFI_IMAGE_DOS_HEADER *DosHeader;\r
1204 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;\r
1205 EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;\r
1206 UINT16 Subsystem;\r
1207\r
1208 if (FileBuffer == NULL || FileSize == 0) {\r
1209 return FALSE;\r
1210 }\r
1211\r
1212 //\r
1213 // Read dos header\r
1214 //\r
1215 DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;\r
1216 if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&\r
1217 FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE\r
1218 ) {\r
1219 //\r
1220 // Read and check PE signature\r
1221 //\r
1222 PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);\r
1223 if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&\r
1224 PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE\r
1225 ) {\r
1226 //\r
1227 // Check PE32 or PE32+ magic, and machine type\r
1228 //\r
1229 OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;\r
d1102dba 1230 if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||\r
067ed98a
RN
1231 OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&\r
1232 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)\r
1233 ) {\r
1234 //\r
1235 // Check the Subsystem:\r
1236 // Driver#### must be of type BootServiceDriver or RuntimeDriver\r
1237 // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application\r
1238 //\r
1239 Subsystem = OptionalHeader->Subsystem;\r
08eff917
RN
1240 if ((Type == LoadOptionTypeMax) ||\r
1241 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||\r
067ed98a
RN
1242 (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||\r
1243 (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
780e05ca
RN
1244 (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||\r
1245 (Type == LoadOptionTypePlatformRecovery && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)\r
067ed98a
RN
1246 ) {\r
1247 return TRUE;\r
1248 }\r
1249 }\r
1250 }\r
1251 }\r
1252\r
1253 return FALSE;\r
1254}\r
1255\r
08eff917
RN
1256/**\r
1257 Return the next matched load option buffer.\r
1258 The routine keeps calling BmGetNextLoadOptionDevicePath() until a valid\r
1259 load option is read.\r
1260\r
1261 @param Type The load option type.\r
1262 It's used to check whether the load option is valid.\r
1263 When it's LoadOptionTypeMax, the routine only guarantees\r
1264 the load option is a valid PE image but doesn't guarantee\r
1265 the PE's subsystem type is valid.\r
1266 @param FilePath The device path pointing to a load option.\r
1267 It could be a short-form device path.\r
1268 @param FullPath Return the next full device path of the load option after\r
1269 short-form device path expanding.\r
1270 Caller is responsible to free it.\r
1271 NULL to return the first matched full device path.\r
1272 @param FileSize Return the load option size.\r
1273\r
1274 @return The load option buffer. Caller is responsible to free the memory.\r
1275**/\r
1276VOID *\r
1277BmGetNextLoadOptionBuffer (\r
1278 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,\r
1279 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1280 OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
1281 OUT UINTN *FileSize\r
1282 )\r
1283{\r
1284 VOID *FileBuffer;\r
1285 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
1286 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
1287 UINTN LocalFileSize;\r
1288 UINT32 AuthenticationStatus;\r
1289 EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;\r
1290\r
1291 LocalFileSize = 0;\r
1292 FileBuffer = NULL;\r
1293 CurFullPath = *FullPath;\r
1294 do {\r
1295 PreFullPath = CurFullPath;\r
1296 CurFullPath = BmGetNextLoadOptionDevicePath (FilePath, CurFullPath);\r
1297 //\r
1298 // Only free the full path created *inside* this routine\r
1299 //\r
1300 if ((PreFullPath != NULL) && (PreFullPath != *FullPath)) {\r
1301 FreePool (PreFullPath);\r
1302 }\r
1303 if (CurFullPath == NULL) {\r
1304 break;\r
1305 }\r
1306 FileBuffer = GetFileBufferByFilePath (TRUE, CurFullPath, &LocalFileSize, &AuthenticationStatus);\r
1307 if ((FileBuffer != NULL) && !BmIsLoadOptionPeHeaderValid (Type, FileBuffer, LocalFileSize)) {\r
1308 //\r
1309 // Free the RAM disk file system if the load option is invalid.\r
1310 //\r
1311 RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);\r
1312 if (RamDiskDevicePath != NULL) {\r
1313 BmDestroyRamDisk (RamDiskDevicePath);\r
1314 FreePool (RamDiskDevicePath);\r
1315 }\r
1316\r
1317 //\r
1318 // Free the invalid load option buffer.\r
1319 //\r
1320 FreePool (FileBuffer);\r
1321 FileBuffer = NULL;\r
1322 }\r
1323 } while (FileBuffer == NULL);\r
1324\r
1325 if (FileBuffer == NULL) {\r
1326 CurFullPath = NULL;\r
1327 LocalFileSize = 0;\r
1328 }\r
1329\r
1330 DEBUG ((DEBUG_INFO, "[Bds] Expand "));\r
1331 BmPrintDp (FilePath);\r
1332 DEBUG ((DEBUG_INFO, " -> "));\r
1333 BmPrintDp (CurFullPath);\r
1334 DEBUG ((DEBUG_INFO, "\n"));\r
1335\r
1336 *FullPath = CurFullPath;\r
1337 *FileSize = LocalFileSize;\r
1338 return FileBuffer;\r
1339}\r
1340\r
067ed98a
RN
1341/**\r
1342 Process (load and execute) the load option.\r
1343\r
1344 @param LoadOption Pointer to the load option.\r
1345\r
d1102dba 1346 @retval EFI_INVALID_PARAMETER The load option type is invalid,\r
067ed98a
RN
1347 or the load option file path doesn't point to a valid file.\r
1348 @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.\r
1349 @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.\r
1350**/\r
1351EFI_STATUS\r
1352EFIAPI\r
1353EfiBootManagerProcessLoadOption (\r
1354 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption\r
1355 )\r
1356{\r
1357 EFI_STATUS Status;\r
08eff917
RN
1358 EFI_DEVICE_PATH_PROTOCOL *PreFullPath;\r
1359 EFI_DEVICE_PATH_PROTOCOL *CurFullPath;\r
067ed98a
RN
1360 EFI_HANDLE ImageHandle;\r
1361 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
1362 VOID *FileBuffer;\r
1363 UINTN FileSize;\r
1364\r
1365 if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {\r
1366 return EFI_INVALID_PARAMETER;\r
1367 }\r
1368\r
1369 if (LoadOption->OptionType == LoadOptionTypeBoot) {\r
1370 return EFI_UNSUPPORTED;\r
1371 }\r
1372\r
1373 //\r
1374 // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
1375 // the boot manager will not automatically load the option.\r
1376 //\r
1377 if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
1378 return EFI_SUCCESS;\r
1379 }\r
1380\r
067ed98a
RN
1381 //\r
1382 // Load and start the load option.\r
1383 //\r
1384 DEBUG ((\r
3fc46b79
RN
1385 DEBUG_INFO | DEBUG_LOAD, "Process %s%04x (%s) ...\n",\r
1386 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber,\r
1387 LoadOption->Description\r
067ed98a
RN
1388 ));\r
1389 ImageHandle = NULL;\r
08eff917
RN
1390 CurFullPath = NULL;\r
1391 EfiBootManagerConnectDevicePath (LoadOption->FilePath, NULL);\r
1392\r
1393 //\r
1394 // while() loop is to keep starting next matched load option if the PlatformRecovery#### returns failure status.\r
1395 //\r
1396 while (TRUE) {\r
1397 Status = EFI_INVALID_PARAMETER;\r
1398 PreFullPath = CurFullPath;\r
1399 FileBuffer = BmGetNextLoadOptionBuffer (LoadOption->OptionType, LoadOption->FilePath, &CurFullPath, &FileSize);\r
1400 if (PreFullPath != NULL) {\r
1401 FreePool (PreFullPath);\r
1402 }\r
1403 if (FileBuffer == NULL) {\r
1404 break;\r
067ed98a 1405 }\r
067ed98a
RN
1406 Status = gBS->LoadImage (\r
1407 FALSE,\r
1408 gImageHandle,\r
08eff917 1409 CurFullPath,\r
067ed98a
RN
1410 FileBuffer,\r
1411 FileSize,\r
1412 &ImageHandle\r
1413 );\r
067ed98a 1414 FreePool (FileBuffer);\r
067ed98a 1415\r
08eff917
RN
1416 if (!EFI_ERROR (Status)) {\r
1417 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);\r
1418 ASSERT_EFI_ERROR (Status);\r
067ed98a 1419\r
08eff917
RN
1420 ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;\r
1421 ImageInfo->LoadOptions = LoadOption->OptionalData;\r
1422 //\r
1423 // Before calling the image, enable the Watchdog Timer for the 5-minute period\r
1424 //\r
1425 gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);\r
067ed98a 1426\r
08eff917
RN
1427 LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);\r
1428 DEBUG ((\r
1429 DEBUG_INFO | DEBUG_LOAD, "%s%04x Return Status = %r\n",\r
1430 mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status\r
067ed98a
RN
1431 ));\r
1432\r
08eff917
RN
1433 //\r
1434 // Clear the Watchdog Timer after the image returns\r
1435 //\r
1436 gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
1437\r
1438 if ((LoadOption->OptionType != LoadOptionTypePlatformRecovery) || (LoadOption->Status == EFI_SUCCESS)) {\r
1439 break;\r
1440 }\r
1441 }\r
1442 }\r
1443\r
1444 if (CurFullPath != NULL) {\r
1445 FreePool (CurFullPath);\r
067ed98a
RN
1446 }\r
1447\r
1448 return Status;\r
1449}\r