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