2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/misc/bcdopt.c
5 * PURPOSE: Boot Library BCD Option Parsing Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 /* FUNCTIONS *****************************************************************/
18 _In_ PBL_BCD_OPTION List
,
22 ULONG_PTR NextOption
= 0, ListOption
;
23 PBL_BCD_OPTION Option
, FoundOption
;
25 /* No options, bail out */
31 /* Loop while we find an option */
35 /* Get the next option and see if it matches the type */
36 Option
= (PBL_BCD_OPTION
)((ULONG_PTR
)List
+ NextOption
);
37 if ((Option
->Type
== Type
) && !(Option
->Empty
))
43 /* Store the offset of the next option */
44 NextOption
= Option
->NextEntryOffset
;
46 /* Failed to match. Check for list options */
47 ListOption
= Option
->ListOffset
;
50 /* Try to get a match in the associated option */
51 Option
= MiscGetBootOption((PBL_BCD_OPTION
)((ULONG_PTR
)Option
+
63 /* Return the option that was found, if any */
68 * @name BlGetBootOptionListSize
70 * The BlGetBootOptionListSize routine
73 * UEFI Image Handle for the current loaded application.
75 * @return Size of the BCD option
79 BlGetBootOptionListSize (
80 _In_ PBL_BCD_OPTION BcdOption
83 ULONG Size
= 0, NextOffset
= 0;
84 PBL_BCD_OPTION NextOption
;
86 /* Loop all the options*/
89 /* Move to the next one */
90 NextOption
= (PBL_BCD_OPTION
)((ULONG_PTR
)BcdOption
+ NextOffset
);
92 /* Compute the size of the next one */
93 Size
+= BlGetBootOptionSize(NextOption
);
95 /* Update the offset */
96 NextOffset
= NextOption
->NextEntryOffset
;
99 /* Return final computed size */
104 * @name BlGetBootOptionSize
106 * The BlGetBootOptionSize routine
109 * UEFI Image Handle for the current loaded application.
111 * @return Size of the BCD option
115 BlGetBootOptionSize (
116 _In_ PBL_BCD_OPTION BcdOption
121 /* Check if there's any data */
122 if (BcdOption
->DataOffset
)
124 /* Add the size of the data */
125 Size
= BcdOption
->DataOffset
+ BcdOption
->DataSize
;
129 /* No data, just the structure itself */
130 Size
= sizeof(*BcdOption
);
133 /* Any associated options? */
134 Offset
= BcdOption
->ListOffset
;
137 /* Go get those too */
138 Size
+= BlGetBootOptionListSize((PVOID
)((ULONG_PTR
)BcdOption
+ Offset
));
141 /* Return the final size */
146 BlGetBootOptionString (
147 _In_ PBL_BCD_OPTION List
,
153 PBL_BCD_OPTION Option
;
154 PWCHAR String
, StringCopy
;
156 BcdElementType ElementType
;
157 //PGUID AppIdentifier;
159 /* Make sure this is a BCD_STRING */
160 ElementType
.PackedValue
= Type
;
161 if (ElementType
.Format
!= BCD_TYPE_STRING
)
163 return STATUS_INVALID_PARAMETER
;
166 /* Return the data */
167 Option
= MiscGetBootOption(List
, Type
);
170 /* Extract the string */
171 String
= (PWCHAR
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
172 Status
= STATUS_SUCCESS
;
176 /* No string is present */
178 Status
= STATUS_NOT_FOUND
;
181 /* Compute the data size */
182 StringLength
= Option
->DataSize
/ sizeof(WCHAR
);
185 /* Filter out SecureBoot Options */
186 AppIdentifier
= BlGetApplicationIdentifier();
187 Status
= BlpBootOptionCallbackString(AppIdentifier
, Type
, String
, StringLength
, &String
, &StringLength
);
191 /* Make sure we have a valid, non-filtered string */
192 if (NT_SUCCESS(Status
))
194 /* Check if we have space for one more character */
195 Status
= RtlULongAdd(StringLength
, 1, &StringLength
);
196 if (NT_SUCCESS(Status
))
198 /* Check if it's safe to multiply by two */
199 Status
= RtlULongMult(StringLength
, sizeof(WCHAR
), &StringLength
);
200 if (NT_SUCCESS(Status
))
202 /* Allocate a copy for the string */
203 StringCopy
= BlMmAllocateHeap(StringLength
);
206 /* NULL-terminate it */
207 RtlCopyMemory(StringCopy
,
209 StringLength
- sizeof(UNICODE_NULL
));
210 StringCopy
[StringLength
] = UNICODE_NULL
;
212 Status
= STATUS_SUCCESS
;
216 /* No memory, fail */
217 Status
= STATUS_NO_MEMORY
;
228 BlGetBootOptionGuid (
229 _In_ PBL_BCD_OPTION List
,
235 PBL_BCD_OPTION Option
;
237 BcdElementType ElementType
;
239 /* Make sure this is a BCD_TYPE_OBJECT */
240 ElementType
.PackedValue
= Type
;
241 if (ElementType
.Format
!= BCD_TYPE_OBJECT
)
243 return STATUS_INVALID_PARAMETER
;
246 /* Return the data */
247 Option
= MiscGetBootOption(List
, Type
);
250 /* Set failure if no data exists */
251 Status
= STATUS_NOT_FOUND
;
256 Guid
= (PGUID
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
257 RtlCopyMemory(Value
, Guid
, Option
->DataSize
);
258 Status
= STATUS_SUCCESS
;
266 BlGetBootOptionGuidList (
267 _In_ PBL_BCD_OPTION List
,
274 PBL_BCD_OPTION Option
;
275 PGUID GuidCopy
, Guid
;
277 BcdElementType ElementType
;
279 /* Make sure this is a BCD_TYPE_OBJECT_LIST */
280 ElementType
.PackedValue
= Type
;
281 if (ElementType
.Format
!= BCD_TYPE_OBJECT_LIST
)
283 return STATUS_INVALID_PARAMETER
;
286 /* Return the data */
287 Option
= MiscGetBootOption(List
, Type
);
290 /* Set failure if no data exists */
291 Status
= STATUS_NOT_FOUND
;
295 /* Get the GUIDs and allocate a copy for them */
296 Guid
= (PGUID
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
297 GuidCopy
= BlMmAllocateHeap(Option
->DataSize
);
301 RtlCopyMemory(GuidCopy
, Guid
, Option
->DataSize
);
303 /* Return the number of GUIDs and the start of the array */
304 GuidCount
= Option
->DataSize
/ sizeof(GUID
);
307 Status
= STATUS_SUCCESS
;
311 /* No memory for the copy */
312 Status
= STATUS_NO_MEMORY
;
321 BlGetBootOptionDevice (
322 _In_ PBL_BCD_OPTION List
,
324 _Out_ PBL_DEVICE_DESCRIPTOR
* Value
,
325 _In_opt_ PBL_BCD_OPTION
* ExtraOptions
329 PBL_BCD_OPTION Option
, ListData
, ListCopy
, SecureListData
;
330 PBCD_DEVICE_OPTION BcdDevice
;
331 ULONG DeviceSize
, ListOffset
, ListSize
;
332 PBL_DEVICE_DESCRIPTOR DeviceDescriptor
, SecureDescriptor
;
333 //PGUID AppIdentifier;
334 BcdElementType ElementType
;
336 /* Make sure this is a BCD_TYPE_DEVICE */
337 ElementType
.PackedValue
= Type
;
338 if (ElementType
.Format
!= BCD_TYPE_DEVICE
)
340 return STATUS_INVALID_PARAMETER
;
343 /* Return the data */
344 Option
= MiscGetBootOption(List
, Type
);
347 /* Set failure if no data exists */
348 Status
= STATUS_NOT_FOUND
;
352 /* Otherwise, read the size of the BCD device encoded */
353 BcdDevice
= (PBCD_DEVICE_OPTION
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
354 DeviceSize
= BcdDevice
->DeviceDescriptor
.Size
;
356 /* Allocate a buffer to copy it into */
357 DeviceDescriptor
= BlMmAllocateHeap(DeviceSize
);
358 if (!DeviceDescriptor
)
360 return STATUS_NO_MEMORY
;
363 /* Copy it into that buffer */
364 RtlCopyMemory(DeviceDescriptor
, &BcdDevice
->DeviceDescriptor
, DeviceSize
);
365 Status
= STATUS_SUCCESS
;
368 /* Check if extra options were requested */
371 /* See where they are */
372 ListOffset
= Option
->ListOffset
;
375 /* See how big they are */
376 ListData
= (PBL_BCD_OPTION
)((ULONG_PTR
)Option
+ ListOffset
);
377 ListSize
= BlGetBootOptionListSize(ListData
);
379 /* Allocate a buffer to hold them into */
380 ListCopy
= BlMmAllocateHeap(ListSize
);
383 Status
= STATUS_NO_MEMORY
;
387 /* Copy them in there */
388 RtlCopyMemory(ListCopy
, ListData
, ListSize
);
393 /* Filter out SecureBoot Options */
394 AppIdentifier
= BlGetApplicationIdentifier();
395 if (BlpBootOptionCallbacks
)
397 DeviceCallback
= BlpBootOptionCallbacks
->Device
;
400 Status
= DeviceCallback(BlpBootOptionCallbackCookie
,
410 /* No secure boot, so the secure descriptors are the standard ones */
411 SecureDescriptor
= DeviceDescriptor
;
412 SecureListData
= ListCopy
;
415 /* Check if the data was read correctly */
416 if (NT_SUCCESS(Status
))
418 /* Check if we had a new descriptor after filtering */
419 if (SecureDescriptor
!= DeviceDescriptor
)
421 /* Yep -- if we had an old one, free it */
422 if (DeviceDescriptor
)
424 BlMmFreeHeap(DeviceDescriptor
);
428 /* Check if we had a new list after filtering */
429 if (SecureListData
!= ListCopy
)
431 /* Yep -- if we had an old list, free it */
434 BlMmFreeHeap(ListCopy
);
438 /* Finally, check if the caller wanted extra options */
441 /* Yep -- so pass the caller our copy */
442 *ExtraOptions
= ListCopy
;
446 /* Caller always wants data back, so pass them our copy */
447 *Value
= DeviceDescriptor
;
448 DeviceDescriptor
= NULL
;
452 /* On the failure path, if these buffers are active, we should free them */
455 BlMmFreeHeap(ListCopy
);
457 if (DeviceDescriptor
)
459 BlMmFreeHeap(DeviceDescriptor
);
467 BlGetBootOptionInteger (
468 _In_ PBL_BCD_OPTION List
,
470 _Out_ PULONGLONG Value
474 PBL_BCD_OPTION Option
;
475 //PGUID AppIdentifier;
476 BcdElementType ElementType
;
478 /* Make sure this is a BCD_TYPE_INTEGER */
479 ElementType
.PackedValue
= Type
;
480 if (ElementType
.Format
!= BCD_TYPE_INTEGER
)
482 return STATUS_INVALID_PARAMETER
;
485 /* Return the data */
486 Option
= MiscGetBootOption(List
, Type
);
489 *Value
= *(PULONGLONG
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
493 /* Filter out SecureBoot Options */
494 AppIdentifier
= BlGetApplicationIdentifier();
495 Status
= BlpBootOptionCallbackULongLong(AppIdentifier
, Type
, Value
);
498 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
504 BlGetBootOptionBoolean (
505 _In_ PBL_BCD_OPTION List
,
511 PBL_BCD_OPTION Option
;
512 //PGUID AppIdentifier;
513 BcdElementType ElementType
;
515 /* Make sure this is a BCD_TYPE_BOOLEAN */
516 ElementType
.PackedValue
= Type
;
517 if (ElementType
.Format
!= BCD_TYPE_BOOLEAN
)
519 return STATUS_INVALID_PARAMETER
;
522 /* Return the data */
523 Option
= MiscGetBootOption(List
, Type
);
526 *Value
= *(PBOOLEAN
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
530 /* Filter out SecureBoot Options */
531 AppIdentifier
= BlGetApplicationIdentifier();
532 Status
= BlpBootOptionCallbackBoolean(AppIdentifier
, Type
, Value
);
535 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
541 BlpGetBootOptionIntegerList (
542 _In_ PBL_BCD_OPTION List
,
544 _Out_ PULONGLONG
* Value
,
545 _Out_ PULONGLONG Count
,
549 PBL_BCD_OPTION Option
;
550 BcdElementType ElementType
;
551 PULONGLONG ValueCopy
;
553 /* Make sure this is a BCD_TYPE_INTEGER_LIST */
554 ElementType
.PackedValue
= Type
;
555 if (ElementType
.Format
!= BCD_TYPE_INTEGER_LIST
)
557 return STATUS_INVALID_PARAMETER
;
560 /* Return the data */
561 Option
= MiscGetBootOption(List
, Type
);
564 return STATUS_NOT_FOUND
;
567 /* Check if a copy should be made of it */
570 /* Nope, return the raw value */
571 *Value
= (PULONGLONG
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
575 /* Allocate a buffer for the copy */
576 ValueCopy
= BlMmAllocateHeap(Option
->DataSize
);
579 return STATUS_NO_MEMORY
;
582 /* Copy the data in */
583 RtlCopyMemory(ValueCopy
,
584 (PVOID
)((ULONG_PTR
)Option
+ Option
->DataOffset
),
587 /* Return our copy */
591 /* Return count and success */
592 *Count
= Option
->DataSize
/ sizeof(ULONGLONG
);
593 return STATUS_SUCCESS
;
598 _In_ PBL_BCD_OPTION OptionList
,
599 _Out_ PBL_BCD_OPTION
*CopiedOptions
604 PBL_BCD_OPTION Options
;
606 /* Assume no options */
607 Status
= STATUS_SUCCESS
;
608 *CopiedOptions
= NULL
;
610 /* Get the size of the list and allocate a copy for it */
611 OptionSize
= BlGetBootOptionListSize(OptionList
);
612 Options
= BlMmAllocateHeap(OptionSize
);
615 return STATUS_NO_MEMORY
;
618 /* Make the copy and return it to the caller */
619 RtlCopyMemory(Options
, OptionList
, OptionSize
);
620 *CopiedOptions
= Options
;
625 BlAppendBootOptionBoolean (
626 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
,
631 PBL_BCD_OPTION Option
;
633 /* Allocate space for the entry -- remember BOOLEANs are USHORTs in BCD */
634 Option
= BlMmAllocateHeap(sizeof(*Option
) + sizeof(USHORT
));
637 return STATUS_NO_MEMORY
;
640 /* Initialize it and set the boolean to TRUE */
641 RtlZeroMemory(Option
, sizeof(*Option
) + sizeof(USHORT
));
642 Option
->DataSize
= sizeof(USHORT
);
643 Option
->Type
= OptionId
;
644 Option
->DataOffset
= sizeof(*Option
);
645 *(PBOOLEAN
)(Option
+ 1) = TRUE
;
648 Status
= BlAppendBootOptions(AppEntry
, Option
);
650 /* We're all done, free our initial option */
651 BlMmFreeHeap(Option
);
656 BlAppendBootOptionInteger (
657 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
,
663 PBL_BCD_OPTION Option
;
665 /* Allocate space for the entry */
666 Option
= BlMmAllocateHeap(sizeof(*Option
) + sizeof(Value
));
669 return STATUS_NO_MEMORY
;
672 /* Initialize it and set the integer to the given value */
673 RtlZeroMemory(Option
, sizeof(*Option
) + sizeof(Value
));
674 Option
->DataSize
= sizeof(Value
);
675 Option
->Type
= OptionId
;
676 Option
->DataOffset
= sizeof(*Option
);
677 *(PULONGLONG
)(Option
+ 1) = Value
;
680 Status
= BlAppendBootOptions(AppEntry
, Option
);
682 /* We're all done, free our initial option */
683 BlMmFreeHeap(Option
);
688 BlAppendBootOptionString (
689 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
,
690 _In_ PWCHAR OptionString
695 PBL_BCD_OPTION Option
;
697 /* Get the length in bytes */
698 Status
= RtlULongLongToULong(wcslen(OptionString
) * sizeof(WCHAR
),
700 if (!NT_SUCCESS(Status
))
705 /* Add a NULL-terminator */
706 Status
= RtlULongAdd(StringSize
, sizeof(UNICODE_NULL
), &StringSize
);
707 if (!NT_SUCCESS(Status
))
712 /* Allocate space for the entry */
713 Option
= BlMmAllocateHeap(sizeof(*Option
) + StringSize
);
716 return STATUS_NO_MEMORY
;
719 /* Initialize it and copy the string value */
720 RtlZeroMemory(Option
, sizeof(*Option
) + StringSize
);
721 Option
->DataSize
= StringSize
;
722 Option
->Type
= BcdLibraryString_ApplicationPath
;
723 Option
->DataOffset
= sizeof(*Option
);
724 wcsncpy((PWCHAR
)Option
+ 1, OptionString
, StringSize
/ sizeof(WCHAR
));
727 Status
= BlAppendBootOptions(AppEntry
, Option
);
729 /* We're all done, free our initial option */
730 BlMmFreeHeap(Option
);
735 BlAppendBootOptions (
736 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
,
737 _In_ PBL_BCD_OPTION Options
740 ULONG OptionsSize
, CurrentSize
;
741 PBL_BCD_OPTION NewOptions
, CurrentOptions
, NextOption
;
745 /* Get the current options */
746 CurrentOptions
= AppEntry
->BcdData
;
748 /* Calculate the size of the current, and the appended options */
749 CurrentSize
= BlGetBootOptionListSize(CurrentOptions
);
750 OptionsSize
= BlGetBootOptionListSize(Options
);
752 /* Allocate a buffer for the concatenated (new) options */
753 NewOptions
= BlMmAllocateHeap(CurrentSize
+ OptionsSize
);
756 return STATUS_NO_MEMORY
;
759 /* Copy the old options, and the ones to be added */
760 RtlCopyMemory(NewOptions
, CurrentOptions
, CurrentSize
);
761 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewOptions
+ CurrentSize
),
766 Status
= STATUS_SUCCESS
;
768 /* Scan through to the last option in the list */
772 NextOption
= (PBL_BCD_OPTION
)((ULONG_PTR
)NewOptions
+ CurrentOffset
);
773 CurrentOffset
= NextOption
->NextEntryOffset
;
774 } while (CurrentOffset
);
776 /* Every other option now has to have its offset adjusted */
779 NextOption
->NextEntryOffset
+= CurrentSize
;
780 NextOption
= (PBL_BCD_OPTION
)((ULONG_PTR
)NewOptions
+ NextOption
->NextEntryOffset
);
781 } while (NextOption
->NextEntryOffset
);
783 /* If we already had internal options, free them */
784 if (AppEntry
->Flags
& BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL
)
786 BlMmFreeHeap(AppEntry
->BcdData
);
789 /* Write the new pointer */
790 AppEntry
->BcdData
= NewOptions
;
792 /* Options are now internal, not external */
793 AppEntry
->Flags
&= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL
;
794 AppEntry
->Flags
|= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL
;
800 _In_ PBL_BCD_OPTION List
,
804 PBL_BCD_OPTION Option
;
806 /* Keep going until the option is gone */
809 /* Get the BCD option */
810 Option
= MiscGetBootOption(List
, Type
);
816 /* Pretend it's empty */
817 Option
->Empty
= TRUE
;
822 BlReplaceBootOptions (
823 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
,
824 _In_ PBL_BCD_OPTION OldOptions
829 PBL_BCD_OPTION NewOptions
;
831 /* Make sure there's something to replace with */
834 return STATUS_INVALID_PARAMETER
;
837 /* Check if we already had allocated internal options */
838 if (AppEntry
->Flags
& BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL
)
841 BlMmFreeHeap(AppEntry
->BcdData
);
844 /* Reset option flags */
845 AppEntry
->Flags
&= ~(BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL
|
846 BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL
);
848 /* Reset the options and set success for now */
849 Status
= STATUS_SUCCESS
;
850 AppEntry
->BcdData
= NULL
;
852 /* Get the size of the new list of options */
853 OptionSize
= BlGetBootOptionListSize(OldOptions
);
855 /* Allocate a copy of the new list */
856 NewOptions
= BlMmAllocateHeap(OptionSize
);
859 return STATUS_NO_MEMORY
;
863 RtlCopyMemory(NewOptions
, OldOptions
, OptionSize
);
865 /* Set it as the new set of options and return */
866 AppEntry
->Flags
|= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL
;
867 AppEntry
->BcdData
= NewOptions
;