]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmLoadOption.c
MdeModulePkg: BaseSortLib and UefiBootManagerLib support DXE_RUNTIME_DRIVER.
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmLoadOption.c
CommitLineData
1d112229
RN
1/** @file
2 Load option library functions which relate with creating and processing load options.
3
4Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "InternalBm.h"
16
17/**
18 Get the Option Number that wasn't used.
19
20 @param OrderVariableName Could be L"BootOrder" or L"DriverOrder".
21 @param FreeOptionNumber To receive the minimal free option number.
22
23 @retval EFI_SUCCESS The option number is found
24 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
25 @retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
26
27**/
28EFI_STATUS
29BmGetFreeOptionNumber (
30 IN CHAR16 *OrderVariableName,
31 OUT UINT16 *FreeOptionNumber
32 )
33{
34
35 UINTN OptionNumber;
36 UINTN Index;
37 UINT16 *OptionOrder;
38 UINTN OptionOrderSize;
39 UINT16 *BootNext;
40
41 if (FreeOptionNumber == NULL) {
42 return EFI_INVALID_PARAMETER;
43 }
44
45 GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, &OptionOrderSize);
46 BootNext = NULL;
47 if (*OrderVariableName == L'B') {
48 GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
49 }
50
51 for (OptionNumber = 0;
52 OptionNumber < OptionOrderSize / sizeof (UINT16)
53 + ((BootNext != NULL) ? 1 : 0);
54 OptionNumber++
55 ) {
56 //
57 // Search in OptionOrder whether the OptionNumber exists
58 //
59 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
60 if (OptionNumber == OptionOrder[Index]) {
61 break;
62 }
63 }
64
65 //
66 // We didn't find it in the ****Order array and it doesn't equal to BootNext
67 // Otherwise, OptionNumber equals to OptionOrderSize / sizeof (UINT16) + 1
68 //
69 if ((Index == OptionOrderSize / sizeof (UINT16)) &&
70 ((BootNext == NULL) || (OptionNumber != *BootNext))
71 ) {
72 break;
73 }
74 }
75 if (OptionOrder != NULL) {
76 FreePool (OptionOrder);
77 }
78
79 if (BootNext != NULL) {
80 FreePool (BootNext);
81 }
82
83 //
84 // When BootOrder & BootNext conver all numbers in the range [0 ... 0xffff],
85 // OptionNumber equals to 0x10000 which is not valid.
86 //
87 ASSERT (OptionNumber <= 0x10000);
88 if (OptionNumber == 0x10000) {
89 return EFI_OUT_OF_RESOURCES;
90 } else {
91 *FreeOptionNumber = (UINT16) OptionNumber;
92 return EFI_SUCCESS;
93 }
94}
95
96/**
97 Update order variable .
98
99 @param OptionOrderName Order variable name which need to be updated.
100 @param OptionNumber Option number for the new option.
101 @param Position Position of the new load option to put in the ****Order variable.
102
103 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
104 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
105 @retval EFI_STATUS Return the status of gRT->SetVariable ().
106
107**/
108EFI_STATUS
109BmAddOptionNumberToOrderVariable (
110 IN CHAR16 *OptionOrderName,
111 IN UINT16 OptionNumber,
112 IN UINTN Position
113 )
114{
115 EFI_STATUS Status;
116 UINTN Index;
117 UINT16 *OptionOrder;
118 UINT16 *NewOptionOrder;
119 UINTN OptionOrderSize;
120 //
121 // Update the option order variable
122 //
123 GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
124
125 Status = EFI_SUCCESS;
126 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
127 if (OptionOrder[Index] == OptionNumber) {
128 Status = EFI_ALREADY_STARTED;
129 break;
130 }
131 }
132
133 if (!EFI_ERROR (Status)) {
134 Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
135
136 NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
137 ASSERT (NewOptionOrder != NULL);
138 if (OptionOrderSize != 0) {
139 CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
140 CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
141 }
142 NewOptionOrder[Position] = OptionNumber;
143
144 Status = gRT->SetVariable (
145 OptionOrderName,
146 &gEfiGlobalVariableGuid,
147 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
148 OptionOrderSize + sizeof (UINT16),
149 NewOptionOrder
150 );
151 FreePool (NewOptionOrder);
152 }
153
154 if (OptionOrder != NULL) {
155 FreePool (OptionOrder);
156 }
157
158 return Status;
159}
160
161/**
162 Create the Boot#### or Driver#### variable from the load option.
163
164 @param LoadOption Pointer to the load option.
165
166 @retval EFI_SUCCESS The variable was created.
167 @retval Others Error status returned by RT->SetVariable.
168**/
169EFI_STATUS
170EFIAPI
171EfiBootManagerLoadOptionToVariable (
172 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Option
173 )
174{
175 UINTN VariableSize;
176 UINT8 *Variable;
177 UINT8 *Ptr;
178 CHAR16 OptionName[sizeof ("Driver####")];
179 CHAR16 *Description;
180 CHAR16 NullChar;
181
182 if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
183 (Option->FilePath == NULL) ||
184 (Option->OptionType >= LoadOptionTypeMax)
185 ) {
186 return EFI_INVALID_PARAMETER;
187 }
188
189 //
190 // Convert NULL description to empty description
191 //
192 NullChar = L'\0';
193 Description = Option->Description;
194 if (Description == NULL) {
195 Description = &NullChar;
196 }
197
198 /*
199 UINT32 Attributes;
200 UINT16 FilePathListLength;
201 CHAR16 Description[];
202 EFI_DEVICE_PATH_PROTOCOL FilePathList[];
203 UINT8 OptionalData[];
204TODO: FilePathList[] IS:
205A packed array of UEFI device paths. The first element of the
206array is a device path that describes the device and location of the
207Image for this load option. The FilePathList[0] is specific
208to the device type. Other device paths may optionally exist in the
209FilePathList, but their usage is OSV specific. Each element
210in the array is variable length, and ends at the device path end
211structure.
212 */
213 VariableSize = sizeof (Option->Attributes)
214 + sizeof (UINT16)
215 + StrSize (Description)
216 + GetDevicePathSize (Option->FilePath)
217 + Option->OptionalDataSize;
218
219 Variable = AllocatePool (VariableSize);
220 ASSERT (Variable != NULL);
221
222 Ptr = Variable;
223 *(UINT32 *) Ptr = Option->Attributes;
224 Ptr += sizeof (Option->Attributes);
225 *(UINT16 *) Ptr = (UINT16) GetDevicePathSize (Option->FilePath);
226 Ptr += sizeof (UINT16);
227 CopyMem (Ptr, Description, StrSize (Description));
228 Ptr += StrSize (Description);
229 CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
230 Ptr += GetDevicePathSize (Option->FilePath);
231 CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
232
233 UnicodeSPrint (
234 OptionName,
235 sizeof (OptionName),
236 (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x",
237 Option->OptionNumber
238 );
239
240 return gRT->SetVariable (
241 OptionName,
242 &gEfiGlobalVariableGuid,
243 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
244 VariableSize,
245 Variable
246 );
247}
248
249/**
250 This function will register the new boot#### or driver#### option.
251 After the boot#### or driver#### updated, the BootOrder or DriverOrder will also be updated.
252
253 @param Option Pointer to load option to add.
254 @param Position Position of the new load option to put in the ****Order variable.
255
256 @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
257 @retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
258 @retval EFI_ALREADY_STARTED The option number of Option is being used already.
259 Note: this API only adds new load option, no replacement support.
260 @retval EFI_OUT_OF_RESOURCES There is no free option number that can be used when the
261 option number specified in the Option is LoadOptionNumberUnassigned.
262 @retval EFI_STATUS Return the status of gRT->SetVariable ().
263
264**/
265EFI_STATUS
266EFIAPI
267EfiBootManagerAddLoadOptionVariable (
268 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
269 IN UINTN Position
270 )
271{
272 EFI_STATUS Status;
273 UINT16 OptionNumber;
274
275 if (Option == NULL) {
276 return EFI_INVALID_PARAMETER;
277 }
278
279 //
280 // Get the free option number if the option number is unassigned
281 //
282 if (Option->OptionNumber == LoadOptionNumberUnassigned) {
283 Status = BmGetFreeOptionNumber (
284 Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
285 &OptionNumber
286 );
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290 Option->OptionNumber = OptionNumber;
291 }
292
293 if (Option->OptionNumber >= LoadOptionNumberMax) {
294 return EFI_INVALID_PARAMETER;
295 }
296
297 Status = BmAddOptionNumberToOrderVariable (
298 Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
299 (UINT16) Option->OptionNumber,
300 Position
301 );
302 if (!EFI_ERROR (Status)) {
303 //
304 // Save the Boot#### or Driver#### variable
305 //
306 Status = EfiBootManagerLoadOptionToVariable (Option);
307 if (EFI_ERROR (Status)) {
308 //
309 // Remove the #### from *Order variable when the Boot####/Driver#### cannot be saved.
310 //
311 EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
312 }
313 }
314
315 return Status;
316}
317
318/**
319 Sort the load option. The DriverOrder or BootOrder will be re-created to
320 reflect the new order.
321
322 @param OptionType Load option type
323 @param CompareFunction The comparator
324**/
325VOID
326EFIAPI
327EfiBootManagerSortLoadOptionVariable (
328 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
329 SORT_COMPARE CompareFunction
330 )
331{
332 EFI_STATUS Status;
333 EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption;
334 UINTN LoadOptionCount;
335 UINTN Index;
336 UINT16 *OptionOrder;
337
338 LoadOption = EfiBootManagerGetLoadOptions (&LoadOptionCount, OptionType);
339
340 //
341 // Insertion sort algorithm
342 //
343 PerformQuickSort (
344 LoadOption,
345 LoadOptionCount,
346 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
347 CompareFunction
348 );
349
350 //
351 // Create new ****Order variable
352 //
353 OptionOrder = AllocatePool (LoadOptionCount * sizeof (UINT16));
354 ASSERT (OptionOrder != NULL);
355 for (Index = 0; Index < LoadOptionCount; Index++) {
356 OptionOrder[Index] = (UINT16) LoadOption[Index].OptionNumber;
357 }
358
359 Status = gRT->SetVariable (
360 OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
361 &gEfiGlobalVariableGuid,
362 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
363 LoadOptionCount * sizeof (UINT16),
364 OptionOrder
365 );
366 //
367 // Changing the *Order content without increasing its size with current variable implementation shouldn't fail.
368 //
369 ASSERT_EFI_ERROR (Status);
370
371 FreePool (OptionOrder);
372 EfiBootManagerFreeLoadOptions (LoadOption, LoadOptionCount);
373}
374
375/**
376 Initialize a load option.
377
378 @param Option Pointer to the load option to be initialized.
379 @param OptionNumber Option number of the load option.
380 @param OptionType Type of the load option.
381 @param Attributes Attributes of the load option.
382 @param Description Description of the load option.
383 @param FilePath Device path of the load option.
384 @param OptionalData Optional data of the load option.
385 @param OptionalDataSize Size of the optional data of the load option.
386
387 @retval EFI_SUCCESS The load option was initialized successfully.
388 @retval EFI_INVALID_PARAMETER Option, Description or FilePath is NULL.
389**/
390EFI_STATUS
391EFIAPI
392EfiBootManagerInitializeLoadOption (
393 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option,
394 IN UINTN OptionNumber,
395 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType,
396 IN UINT32 Attributes,
397 IN CHAR16 *Description,
398 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
399 IN UINT8 *OptionalData, OPTIONAL
400 IN UINT32 OptionalDataSize
401 )
402{
403 if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {
404 return EFI_INVALID_PARAMETER;
405 }
406
407 if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||
408 ((OptionalData == NULL) && (OptionalDataSize != 0))) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
413 Option->OptionNumber = OptionNumber;
414 Option->OptionType = OptionType;
415 Option->Attributes = Attributes;
416 Option->Description = AllocateCopyPool (StrSize (Description), Description);
417 Option->FilePath = DuplicateDevicePath (FilePath);
418 if (OptionalData != NULL) {
419 Option->OptionalData = AllocateCopyPool (OptionalDataSize, OptionalData);
420 Option->OptionalDataSize = OptionalDataSize;
421 }
422
423 return EFI_SUCCESS;
424}
425
426
427/**
428 Return the index of the load option in the load option array.
429
430 The function consider two load options are equal when the
431 OptionType, Attributes, Description, FilePath and OptionalData are equal.
432
433 @param Key Pointer to the load option to be found.
434 @param Array Pointer to the array of load options to be found.
435 @param Count Number of entries in the Array.
436
437 @retval -1 Key wasn't found in the Array.
438 @retval 0 ~ Count-1 The index of the Key in the Array.
439**/
440INTN
441BmFindLoadOption (
442 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
443 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
444 IN UINTN Count
445 )
446{
447 UINTN Index;
448
449 for (Index = 0; Index < Count; Index++) {
450 if ((Key->OptionType == Array[Index].OptionType) &&
451 (Key->Attributes == Array[Index].Attributes) &&
452 (StrCmp (Key->Description, Array[Index].Description) == 0) &&
453 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
454 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
455 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
456 return (INTN) Index;
457 }
458 }
459
460 return -1;
461}
462
463/**
464 Update the BootOrder or DriverOrder to delete OptionNumber .
465
466 @param OptionOrderVariable Order variable name which need to be updated.
467 @param OptionNumber Indicate the option number of load option
468
469 @retval EFI_NOT_FOUND The load option cannot be found
470 @retval EFI_SUCCESS The load option was deleted
471 @retval others Status of RT->SetVariable()
472**/
473EFI_STATUS
474BmDeleteOptionVariable (
475 IN CHAR16 *OptionOrderVariable,
476 IN UINT16 OptionNumber
477 )
478{
479 UINT16 *OptionOrder;
480 UINTN OptionOrderSize;
481 EFI_STATUS Status;
482 UINTN Index;
483
484 Status = EFI_NOT_FOUND;
485 GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, &OptionOrderSize);
486 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
487 if (OptionOrder[Index] == OptionNumber) {
488 OptionOrderSize -= sizeof (UINT16);
489 CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
490 Status = gRT->SetVariable (
491 OptionOrderVariable,
492 &gEfiGlobalVariableGuid,
493 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
494 OptionOrderSize,
495 OptionOrder
496 );
497 break;
498 }
499 }
500 if (OptionOrder != NULL) {
501 FreePool (OptionOrder);
502 }
503
504 return Status;
505}
506
507/**
508 Update the BootOrder or DriverOrder according to the OptionType to delete OptionNumber .
509
510 @param OptionNumber Indicate the option number of load option
511 @param OptionType Indicate the type of load option
512
513 @retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
514 @retval EFI_NOT_FOUND The load option cannot be found
515 @retval EFI_SUCCESS The load option was deleted
516**/
517EFI_STATUS
518EFIAPI
519EfiBootManagerDeleteLoadOptionVariable (
520 IN UINTN OptionNumber,
521 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
522 )
523{
524 if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
525 return EFI_INVALID_PARAMETER;
526 }
527
528 return BmDeleteOptionVariable (
529 OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
530 (UINT16) OptionNumber
531 );
532}
533
534/**
535 Convert a single character to number.
536 It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
537
538 @param Char The input char which need to convert to int.
539**/
540UINTN
541BmCharToUint (
542 IN CHAR16 Char
543 )
544{
545 if ((Char >= L'0') && (Char <= L'9')) {
546 return (UINTN) (Char - L'0');
547 }
548
549 if ((Char >= L'A') && (Char <= L'F')) {
550 return (UINTN) (Char - L'A' + 0xA);
551 }
552
553 ASSERT (FALSE);
554 return 0;
555}
556
557/**
558 Returns the size of a device path in bytes.
559
560 This function returns the size, in bytes, of the device path data structure
561 specified by DevicePath including the end of device path node. If DevicePath
562 is NULL, then 0 is returned. If the length of the device path is bigger than
563 MaxSize, also return 0 to indicate this is an invalidate device path.
564
565 @param DevicePath A pointer to a device path data structure.
566 @param MaxSize Max valid device path size. If big than this size,
567 return error.
568
569 @retval 0 An invalid device path.
570 @retval Others The size of a device path in bytes.
571
572**/
573UINTN
574BmGetDevicePathSizeEx (
575 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
576 IN UINTN MaxSize
577 )
578{
579 UINTN Size;
580 UINTN NodeSize;
581
582 if (DevicePath == NULL) {
583 return 0;
584 }
585
586 //
587 // Search for the end of the device path structure
588 //
589 Size = 0;
590 while (!IsDevicePathEnd (DevicePath)) {
591 NodeSize = DevicePathNodeLength (DevicePath);
592 if (NodeSize == 0) {
593 return 0;
594 }
595 Size += NodeSize;
596 if (Size > MaxSize) {
597 return 0;
598 }
599 DevicePath = NextDevicePathNode (DevicePath);
600 }
601 Size += DevicePathNodeLength (DevicePath);
602 if (Size > MaxSize) {
603 return 0;
604 }
605
606 return Size;
607}
608
609/**
610 Returns the length of a Null-terminated Unicode string. If the length is
611 bigger than MaxStringLen, return length 0 to indicate that this is an
612 invalidate string.
613
614 This function returns the number of Unicode characters in the Null-terminated
615 Unicode string specified by String.
616
617 If String is NULL, then ASSERT().
618 If String is not aligned on a 16-bit boundary, then ASSERT().
619
620 @param String A pointer to a Null-terminated Unicode string.
621 @param MaxStringLen Max string len in this string.
622
623 @retval 0 An invalid string.
624 @retval Others The length of String.
625
626**/
627UINTN
628BmStrSizeEx (
629 IN CONST CHAR16 *String,
630 IN UINTN MaxStringLen
631 )
632{
633 UINTN Length;
634
635 ASSERT (String != NULL && MaxStringLen != 0);
636 ASSERT (((UINTN) String & BIT0) == 0);
637
638 for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
639
640 if (*String != L'\0' && MaxStringLen == Length) {
641 return 0;
642 }
643
644 return Length + 2;
645}
646
647/**
648 Validate the EFI Boot#### variable (VendorGuid/Name)
649
650 @param Variable Boot#### variable data.
651 @param VariableSize Returns the size of the EFI variable that was read
652
653 @retval TRUE The variable data is correct.
654 @retval FALSE The variable data is corrupted.
655
656**/
657BOOLEAN
658BmValidateOption (
659 UINT8 *Variable,
660 UINTN VariableSize
661 )
662{
663 UINT16 FilePathSize;
664 UINT8 *TempPtr;
665 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
666 UINTN TempSize;
667
668 if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
669 return FALSE;
670 }
671
672 //
673 // Skip the option attribute
674 //
675 TempPtr = Variable;
676 TempPtr += sizeof (UINT32);
677
678 //
679 // Get the option's device path size
680 //
681 FilePathSize = *(UINT16 *) TempPtr;
682 TempPtr += sizeof (UINT16);
683
684 //
685 // Get the option's description string size
686 //
687 TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
688 TempPtr += TempSize;
689
690 //
691 // Get the option's device path
692 //
693 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
694 TempPtr += FilePathSize;
695
696 //
697 // Validation boot option variable.
698 //
699 if ((FilePathSize == 0) || (TempSize == 0)) {
700 return FALSE;
701 }
702
703 if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
704 return FALSE;
705 }
706
707 return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
708}
709
710/**
711 Build the Boot#### or Driver#### option from the VariableName.
712
713 @param VariableName EFI Variable name indicate if it is Boot#### or
714 Driver####
715 @param Option Return the Boot#### or Driver#### option.
716
717 @retval EFI_SUCCESS Get the option just been created
718 @retval EFI_NOT_FOUND Failed to get the new option
719
720**/
721EFI_STATUS
722EFIAPI
723EfiBootManagerVariableToLoadOption (
724 IN CHAR16 *VariableName,
725 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
726 )
727{
728 EFI_STATUS Status;
729 UINT32 Attribute;
730 UINT16 FilePathSize;
731 UINT8 *Variable;
732 UINT8 *TempPtr;
733 UINTN VariableSize;
734 EFI_DEVICE_PATH_PROTOCOL *FilePath;
735 UINT8 *OptionalData;
736 UINT32 OptionalDataSize;
737 CHAR16 *Description;
738 UINT8 NumOff;
739 EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
740 UINT16 OptionNumber;
741
742 if ((VariableName == NULL) || (Option == NULL)) {
743 return EFI_INVALID_PARAMETER;
744 }
745
746 //
747 // Read the variable
748 //
749 GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize);
750 if (Variable == NULL) {
751 return EFI_NOT_FOUND;
752 }
753
754 //
755 // Validate Boot#### variable data.
756 //
757 if (!BmValidateOption(Variable, VariableSize)) {
758 FreePool (Variable);
759 return EFI_INVALID_PARAMETER;
760 }
761
762 //
763 // Notes: careful defined the variable of Boot#### or
764 // Driver####, consider use some macro to abstract the code
765 //
766 //
767 // Get the option attribute
768 //
769 TempPtr = Variable;
770 Attribute = *(UINT32 *) Variable;
771 TempPtr += sizeof (UINT32);
772
773 //
774 // Get the option's device path size
775 //
776 FilePathSize = *(UINT16 *) TempPtr;
777 TempPtr += sizeof (UINT16);
778
779 //
780 // Get the option's description string
781 //
782 Description = (CHAR16 *) TempPtr;
783
784 //
785 // Get the option's description string size
786 //
787 TempPtr += StrSize ((CHAR16 *) TempPtr);
788
789 //
790 // Get the option's device path
791 //
792 FilePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
793 TempPtr += FilePathSize;
794
795 OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
796 if (OptionalDataSize == 0) {
797 OptionalData = NULL;
798 } else {
799 OptionalData = TempPtr;
800 }
801
802 if (*VariableName == L'B') {
803 OptionType = LoadOptionTypeBoot;
804 NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
805 } else {
806 OptionType = LoadOptionTypeDriver;
807 NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1);
808 }
809
810 //
811 // Get the value from VariableName Unicode string
812 // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
813 // Unicode stream to ASCII without any loss in meaning.
814 //
815 OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000)
816 + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100)
817 + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10)
818 + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1);
819
820 Status = EfiBootManagerInitializeLoadOption (
821 Option,
822 OptionNumber,
823 OptionType,
824 Attribute,
825 Description,
826 FilePath,
827 OptionalData,
828 OptionalDataSize
829 );
830 ASSERT_EFI_ERROR (Status);
831
832 FreePool (Variable);
833 return Status;
834}
835
836/**
837 Returns an array of load options based on the EFI variable
838 L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
839 #### is the hex value of the UINT16 in each BootOrder/DriverOrder entry.
840
841 @param LoadOptionCount Returns number of entries in the array.
842 @param LoadOptionType The type of the load option.
843
844 @retval NULL No load options exist.
845 @retval !NULL Array of load option entries.
846
847**/
848EFI_BOOT_MANAGER_LOAD_OPTION *
849EFIAPI
850EfiBootManagerGetLoadOptions (
851 OUT UINTN *OptionCount,
852 IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType
853 )
854{
855 EFI_STATUS Status;
856 UINT16 *OptionOrder;
857 UINTN OptionOrderSize;
858 UINTN Index;
859 UINTN OptionIndex;
860 EFI_BOOT_MANAGER_LOAD_OPTION *Option;
861 CHAR16 OptionName[sizeof ("Driver####")];
862 UINT16 OptionNumber;
863
864 *OptionCount = 0;
865
866 //
867 // Read the BootOrder, or DriverOrder variable.
868 //
869 GetEfiGlobalVariable2 (
870 (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder",
871 (VOID **) &OptionOrder,
872 &OptionOrderSize
873 );
874 if (OptionOrder == NULL) {
875 return NULL;
876 }
877
878 *OptionCount = OptionOrderSize / sizeof (UINT16);
879
880 Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
881 ASSERT (Option != NULL);
882
883 OptionIndex = 0;
884 for (Index = 0; Index < *OptionCount; Index++) {
885 OptionNumber = OptionOrder[Index];
886 if (LoadOptionType == LoadOptionTypeBoot) {
887 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber);
888 } else {
889 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionNumber);
890 }
891
892 Status = EfiBootManagerVariableToLoadOption (OptionName, &Option[OptionIndex]);
893 if (EFI_ERROR (Status)) {
894 DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
895 EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionTypeBoot);
896 } else {
897 ASSERT (Option[OptionIndex].OptionNumber == OptionNumber);
898 OptionIndex++;
899 }
900 }
901
902 if (OptionOrder != NULL) {
903 FreePool (OptionOrder);
904 }
905
906 if (OptionIndex < *OptionCount) {
907 Option = ReallocatePool (
908 *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
909 OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
910 Option
911 );
912 ASSERT (Option != NULL);
913 *OptionCount = OptionIndex;
914 }
915
916 return Option;
917}
918
919/**
920 Free an EFI_BOOT_MANGER_LOAD_OPTION entry that was allocate by the library.
921
922 @param LoadOption Pointer to boot option to Free.
923
924 @return EFI_SUCCESS BootOption was freed
925 @return EFI_NOT_FOUND BootOption == NULL
926
927**/
928EFI_STATUS
929EFIAPI
930EfiBootManagerFreeLoadOption (
931 IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
932 )
933{
934 if (LoadOption == NULL) {
935 return EFI_NOT_FOUND;
936 }
937
938 if (LoadOption->Description != NULL) {
939 FreePool (LoadOption->Description);
940 }
941 if (LoadOption->FilePath != NULL) {
942 FreePool (LoadOption->FilePath);
943 }
944 if (LoadOption->OptionalData != NULL) {
945 FreePool (LoadOption->OptionalData);
946 }
947
948 return EFI_SUCCESS;
949}
950
951/**
952 Free an EFI_BOOT_MANGER_LOAD_OPTION array that was allocated by
953 EfiBootManagerGetLoadOptions().
954
955 @param Option Pointer to boot option array to free.
956 @param OptionCount Number of array entries in BootOption
957
958 @return EFI_SUCCESS BootOption was freed
959 @return EFI_NOT_FOUND BootOption == NULL
960
961**/
962EFI_STATUS
963EFIAPI
964EfiBootManagerFreeLoadOptions (
965 IN EFI_BOOT_MANAGER_LOAD_OPTION *Option,
966 IN UINTN OptionCount
967 )
968{
969 UINTN Index;
970
971 if (Option == NULL) {
972 return EFI_NOT_FOUND;
973 }
974
975 for (Index = 0;Index < OptionCount; Index++) {
976 EfiBootManagerFreeLoadOption (&Option[Index]);
977 }
978
979 FreePool (Option);
980
981 return EFI_SUCCESS;
982}