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