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