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