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