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