2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/misc/bcd.c
5 * PURPOSE: Boot Library BCD Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 /* FUNCTIONS *****************************************************************/
17 BiNotifyEnumerationError (
18 _In_ HANDLE ObjectHandle
,
19 _In_ PWCHAR ElementName
,
24 UNREFERENCED_PARAMETER(ObjectHandle
);
25 UNREFERENCED_PARAMETER(ElementName
);
26 UNREFERENCED_PARAMETER(Status
);
27 EfiPrintf(L
"Error in BiNotify: %lx for element %s\r\n", Status
, ElementName
);
31 BiConvertElementFormatToValueType (
35 /* Strings and objects are strings */
36 if ((Format
== BCD_TYPE_STRING
) || (Format
== BCD_TYPE_OBJECT
))
41 /* Object lists are arrays of strings */
42 if (Format
== BCD_TYPE_OBJECT_LIST
)
47 /* Everything else is binary */
52 BiConvertRegistryDataToElement (
53 _In_ HANDLE ObjectHandle
,
55 _In_ ULONG DataLength
,
56 _In_ BcdElementType ElementType
,
58 _Out_ PULONG ElementSize
62 ULONG Length
, Size
, ReturnedLength
;
63 PBL_DEVICE_DESCRIPTOR Device
;
64 BOOLEAN NullTerminate
;
65 PBCD_DEVICE_OPTION BcdDevice
, ElementDevice
;
66 PWCHAR BcdString
, ElementString
;
67 PGUID ElementGuid
; UNICODE_STRING GuidString
;
68 PULONGLONG ElementInteger
;
69 PUSHORT ElementWord
; PBOOLEAN BcdBoolean
;
74 /* Check what type of format we are dealing with */
75 switch (ElementType
.Format
)
77 /* Devices -- they are in a binary format */
80 /* First, make sure it's at least big enough for an empty descriptor */
81 if (DataLength
< FIELD_OFFSET(BCD_DEVICE_OPTION
,
82 DeviceDescriptor
.Unknown
))
84 return STATUS_OBJECT_TYPE_MISMATCH
;
87 /* Both the registry and BCD format are the same */
88 BcdDevice
= (PBCD_DEVICE_OPTION
)Data
;
89 ElementDevice
= (PBCD_DEVICE_OPTION
)Element
;
91 /* Make sure the device fits in the registry data */
92 Device
= &BcdDevice
->DeviceDescriptor
;
94 if ((Size
+ sizeof(BcdDevice
->AssociatedEntry
)) != DataLength
)
96 return STATUS_OBJECT_TYPE_MISMATCH
;
99 /* Check if this is a locate device */
100 if (Device
->DeviceType
== LocateDevice
)
102 EfiPrintf(L
"Locates not yet supported\r\n");
103 return STATUS_NOT_SUPPORTED
;
106 /* Make sure the caller's buffer can fit the device */
107 ReturnedLength
= Size
+ sizeof(BcdDevice
->AssociatedEntry
);
108 if (ReturnedLength
> *ElementSize
)
110 Status
= STATUS_BUFFER_TOO_SMALL
;
114 /* It'll fit -- copy it in */
115 RtlCopyMemory(&ElementDevice
->DeviceDescriptor
, Device
, Size
);
116 ElementDevice
->AssociatedEntry
= BcdDevice
->AssociatedEntry
;
117 Status
= STATUS_SUCCESS
;
120 /* Strings -- they are stored as is */
121 case BCD_TYPE_STRING
:
123 /* Make sure the string isn't empty or misaligned */
124 if (!(DataLength
) || (DataLength
& 1))
126 return STATUS_OBJECT_TYPE_MISMATCH
;
129 /* Both the registry and BCD format are the same */
130 BcdString
= (PWCHAR
)Data
;
131 ElementString
= (PWCHAR
)Element
;
133 /* We'll need as much data as the string has to offer */
134 ReturnedLength
= DataLength
;
136 /* If the string isn't NULL-terminated, do it now */
137 NullTerminate
= FALSE
;
138 if (BcdString
[(DataLength
/ sizeof(WCHAR
)) - 1] != UNICODE_NULL
)
140 ReturnedLength
+= sizeof(UNICODE_NULL
);
141 NullTerminate
= TRUE
;
144 /* Will we fit in the caller's buffer? */
145 if (ReturnedLength
> *ElementSize
)
147 Status
= STATUS_BUFFER_TOO_SMALL
;
151 /* Yep -- copy it in, and NULL-terminate if needed */
152 RtlCopyMemory(Element
, Data
, DataLength
);
155 ElementString
[DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
158 Status
= STATUS_SUCCESS
;
161 /* Objects -- they are stored as GUID Strings */
162 case BCD_TYPE_OBJECT
:
164 /* Registry data is a string, BCD data is a GUID */
165 BcdString
= (PWCHAR
)Data
;
166 ElementGuid
= (PGUID
)Element
;
168 /* We need a GUID-sized buffer, does the caller have one? */
169 ReturnedLength
= sizeof(*ElementGuid
);
170 if (*ElementSize
< ReturnedLength
)
172 Status
= STATUS_BUFFER_TOO_SMALL
;
176 /* Yep, copy the GUID */
177 RtlInitUnicodeString(&GuidString
, BcdString
);
178 Status
= RtlGUIDFromString(&GuidString
, ElementGuid
);
181 /* Object Lists -- they are stored as arrays of GUID strings */
182 case BCD_TYPE_OBJECT_LIST
:
184 /* Assume an empty list*/
187 Status
= STATUS_SUCCESS
;
189 /* Registry data is an array of strings, BCD data is array of GUIDs */
190 BcdString
= (PWCHAR
)Data
;
191 ElementGuid
= (PGUID
)Element
;
193 /* Loop as long as the array still has strings */
196 /* Don't read beyond the registry data */
197 if (Length
>= DataLength
)
202 /* One more GUID -- does the caller have space? */
203 ReturnedLength
+= sizeof(GUID
);
204 if (ReturnedLength
<= *ElementSize
)
206 /* Convert and add it in */
207 RtlInitUnicodeString(&GuidString
, BcdString
);
208 Status
= RtlGUIDFromString(&GuidString
, ElementGuid
);
209 if (!NT_SUCCESS(Status
))
214 /* Move to the next GUID in the caller's buffer */
218 /* Move to the next string in the registry array */
219 Size
= (wcslen(BcdString
) * sizeof(WCHAR
)) + sizeof(UNICODE_NULL
);
221 BcdString
= (PWCHAR
)((ULONG_PTR
)BcdString
+ Length
);
224 /* Check if we failed anywhere */
225 if (!NT_SUCCESS(Status
))
230 /* Check if we consumed more space than we have */
231 if (ReturnedLength
> *ElementSize
)
233 Status
= STATUS_BUFFER_TOO_SMALL
;
239 /* Integer -- stored as binary */
240 case BCD_TYPE_INTEGER
:
242 /* BCD data is a ULONGLONG, registry data is 8 bytes binary */
243 ElementInteger
= (PULONGLONG
)Element
;
244 ReturnedLength
= sizeof(*ElementInteger
);
246 /* Make sure the registry data makes sense */
247 if (DataLength
> ReturnedLength
)
249 return STATUS_OBJECT_TYPE_MISMATCH
;
252 /* Make sure the caller has space */
253 if (*ElementSize
< ReturnedLength
)
255 Status
= STATUS_BUFFER_TOO_SMALL
;
259 /* Write the integer result */
261 RtlCopyMemory(ElementInteger
, Data
, DataLength
);
262 Status
= STATUS_SUCCESS
;
265 /* Boolean -- stored as binary */
266 case BCD_TYPE_BOOLEAN
:
268 /* BCD data is a BOOLEAN, registry data is 2 bytes binary */
269 ElementWord
= (PUSHORT
)Element
;
270 BcdBoolean
= (PBOOLEAN
)Data
;
271 ReturnedLength
= sizeof(ElementWord
);
273 /* Make sure the registry data makes sense */
274 if (DataLength
!= sizeof(*BcdBoolean
))
276 return STATUS_OBJECT_TYPE_MISMATCH
;
279 /* Make sure the caller has space */
280 if (*ElementSize
< ReturnedLength
)
282 Status
= STATUS_BUFFER_TOO_SMALL
;
286 /* Write the boolean result */
288 *ElementWord
= *BcdBoolean
!= 0;
289 Status
= STATUS_SUCCESS
;
292 /* Integer list --stored as binary */
293 case BCD_TYPE_INTEGER_LIST
:
295 /* BCD Data is n ULONGLONGs, registry data is n*8 bytes binary */
296 ReturnedLength
= DataLength
;
297 if (!(DataLength
) || (DataLength
& 7))
299 return STATUS_OBJECT_TYPE_MISMATCH
;
302 /* Make sure the caller has space */
303 if (*ElementSize
< ReturnedLength
)
305 Status
= STATUS_BUFFER_TOO_SMALL
;
309 /* Write the integer list result */
310 RtlCopyMemory(Element
, Data
, DataLength
);
311 Status
= STATUS_SUCCESS
;
317 /* Registry data is copied binary as-is */
318 ReturnedLength
= DataLength
;
320 /* Make sure it's not empty */
323 return STATUS_OBJECT_TYPE_MISMATCH
;
326 /* Make sure the caller has space */
327 if (*ElementSize
< ReturnedLength
)
329 Status
= STATUS_BUFFER_TOO_SMALL
;
333 /* Write the result */
334 RtlCopyMemory(Element
, Data
, DataLength
);
335 Status
= STATUS_SUCCESS
;
339 /* If we got here due to success or space issues, write the size */
340 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
342 *ElementSize
= ReturnedLength
;
345 /* All done, return our conversion result */
350 BiConvertBcdElements (
351 _In_ PBCD_PACKED_ELEMENT Elements
,
352 _Out_opt_ PBCD_ELEMENT Buffer
,
353 _Inout_ PULONG BufferSize
,
354 _Inout_ PULONG ElementCount
358 ULONG ElementSize
, AlignedElementSize
, AlignedDataSize
;
359 PBCD_ELEMENT_HEADER Header
;
364 /* Local variable to keep track of objects */
367 /* Safely compute the element bytes needed */
368 Status
= RtlULongMult(*ElementCount
, sizeof(BCD_ELEMENT
), &ElementSize
);
369 if (!NT_SUCCESS(Status
))
374 /* Safely align the element size */
375 Status
= RtlULongAdd(ElementSize
,
377 &AlignedElementSize
);
378 if (!NT_SUCCESS(Status
))
382 AlignedElementSize
= ALIGN_DOWN(AlignedElementSize
, ULONG
);
384 /* Do a safe version of Add2Ptr to figure out where the headers will start */
385 Status
= RtlULongPtrAdd((ULONG_PTR
)Buffer
,
387 (PULONG_PTR
)&Header
);
388 if (!NT_SUCCESS(Status
))
393 /* Safely compute the header bytes needed */
394 Status
= RtlULongMult(*ElementCount
,
395 sizeof(BCD_ELEMENT_HEADER
),
397 if (!NT_SUCCESS(Status
))
402 /* Safely align the header size */
403 Status
= RtlULongAdd(ElementSize
,
404 AlignedElementSize
+ sizeof(ULONG
) - 1,
405 &AlignedElementSize
);
406 if (!NT_SUCCESS(Status
))
410 AlignedElementSize
= ALIGN_DOWN(AlignedElementSize
, ULONG
);
412 /* Do a safe version of Add2Ptr */
413 Status
= RtlULongPtrAdd((ULONG_PTR
)Buffer
,
416 if (!NT_SUCCESS(Status
))
421 /* Iterate over every element */
422 for (i
= 0; i
< *ElementCount
; i
++)
424 /* Safely align the element size */
425 Status
= RtlULongAdd(Elements
->Size
,
428 if (!NT_SUCCESS(Status
))
432 AlignedDataSize
= ALIGN_DOWN(AlignedDataSize
, ULONG
);
434 /* Safely add the size of this data element */
435 Status
= RtlULongAdd(AlignedElementSize
,
437 &AlignedElementSize
);
438 if (!NT_SUCCESS(Status
))
443 /* Do we have enough space left? */
444 if (*BufferSize
>= AlignedElementSize
)
446 /* Check if our root is an inherited object */
448 if (Elements
->RootType
.PackedValue
== BcdLibraryObjectList_InheritedObjects
)
450 /* Yes, scan for us in the current buffer */
451 for (j
= 0; j
< Count
; j
++)
453 /* Do we already exist? */
454 while (Buffer
[j
].Header
->Type
== Elements
->RootType
.PackedValue
)
463 /* Have we already found ourselves? */
466 /* Nope, one more entry */
469 /* Write out the unpacked object */
471 Buffer
->Header
= Header
;
473 /* Fill out its header */
474 Header
->Size
= Elements
->Size
;
475 Header
->Type
= Elements
->Type
;
476 Header
->Version
= Elements
->Version
;
478 /* And copy the data */
479 RtlCopyMemory(Data
, Elements
->Data
, Header
->Size
);
481 /* Move to the next unpacked object and header */
485 /* Move to the next data entry */
486 Data
= (PVOID
)((ULONG_PTR
)Data
+ AlignedDataSize
);
491 /* Nope, set failure code, but keep going so we can return count */
492 Status
= STATUS_BUFFER_TOO_SMALL
;
495 /* Move to the next element entry */
496 Elements
= Elements
->NextEntry
;
499 /* Return the new final buffer size and count */
500 *BufferSize
= AlignedElementSize
;
501 *ElementCount
= Count
;
507 _In_ HANDLE BcdHandle
,
509 _Out_ PHANDLE ObjectHandle
514 UNICODE_STRING GuidString
;
515 HANDLE RootObjectHandle
;
518 *ObjectHandle
= NULL
;
520 /* Initialize GUID string */
521 GuidString
.Buffer
= NULL
;
523 /* Open the root "Objects" handle */
524 RootObjectHandle
= NULL
;
525 Status
= BiOpenKey(BcdHandle
, L
"Objects", &RootObjectHandle
);
526 if (!NT_SUCCESS(Status
))
531 /* Capture the object ID and convert it into a string */
532 LocalGuid
= *ObjectId
;
533 Status
= RtlStringFromGUID(&LocalGuid
, &GuidString
);
534 if (!NT_SUCCESS(Status
))
539 /* Now open the key containing this object ID */
540 Status
= BiOpenKey(RootObjectHandle
, GuidString
.Buffer
, ObjectHandle
);
543 /* Free the GUID string if we had one allocated */
544 if (GuidString
.Buffer
)
546 RtlFreeUnicodeString(&GuidString
);
549 /* Close the root handle if it was open */
550 if (RootObjectHandle
)
552 BiCloseKey(RootObjectHandle
);
555 /* Return the final status */
561 _In_ HANDLE ObjectHandle
,
566 HANDLE ElementsHandle
, ElementHandle
;
567 WCHAR TypeString
[22];
569 /* Open the elements key */
570 Status
= BiOpenKey(ObjectHandle
, L
"Elements", &ElementsHandle
);
571 if (NT_SUCCESS(Status
))
573 /* Convert the element ID into a string */
574 if (!_ultow(Type
, TypeString
, 16))
576 /* Failed to do so */
577 Status
= STATUS_UNSUCCESSFUL
;
581 /* Open the element specifically */
582 Status
= BiOpenKey(ElementsHandle
, TypeString
, &ElementHandle
);
583 if (NT_SUCCESS(Status
))
586 Status
= BiDeleteKey(ElementHandle
);
587 if (NT_SUCCESS(Status
))
589 /* No point in closing the handle anymore */
590 ElementHandle
= NULL
;
595 /* The element doesn't exist */
596 Status
= STATUS_NOT_FOUND
;
599 /* Check if we should close the key */
603 BiCloseKey(ElementHandle
);
608 /* Check if we should close the elements handle */
612 BiCloseKey(ElementsHandle
);
615 /* Return whatever the result was */
620 BiEnumerateSubElements (
621 _In_ HANDLE BcdHandle
,
623 _In_ ULONG ElementType
,
625 _Out_opt_ PBCD_PACKED_ELEMENT
* Elements
,
626 _Inout_ PULONG ElementSize
,
627 _Out_ PULONG ElementCount
631 PBCD_PACKED_ELEMENT Element
;
633 ULONG ParsedElements
, RequiredSize
;
640 /* Open the object */
641 Status
= BcdOpenObject(BcdHandle
, Object
, &ObjectHandle
);
642 if (!NT_SUCCESS(Status
))
647 /* Read the first entry, and the size available */
649 RequiredSize
= *ElementSize
;
651 /* Enumerate the object into the element array */
652 Status
= BiEnumerateElements(BcdHandle
,
660 /* Close the handle and bail out if we couldn't enumerate */
661 BiCloseKey(ObjectHandle
);
662 if (!NT_SUCCESS(Status
))
667 /* Check if the and subelements were present */
670 /* Keep going until the last one */
671 while (Element
->NextEntry
)
673 Element
= Element
->NextEntry
;
676 /* Set the new buffer location to the last element */
681 /* Return the number of sub-elements and their size */
682 *ElementCount
= ParsedElements
;
683 *ElementSize
= RequiredSize
;
688 BiEnumerateSubObjectElements (
689 _In_ HANDLE BcdHandle
,
690 _Out_ PGUID SubObjectList
,
691 _In_ ULONG SubObjectCount
,
693 _Out_opt_ PBCD_PACKED_ELEMENT Elements
,
694 _Inout_ PULONG ElementSize
,
695 _Out_ PULONG ElementCount
699 ULONG SubElementCount
, TotalSize
, RequiredSize
, CurrentSize
, i
;
700 PBCD_PACKED_ELEMENT PreviousElement
;
702 /* Assume empty list */
704 Status
= STATUS_SUCCESS
;
706 /* Initialize variables */
708 PreviousElement
= NULL
;
710 /* Set the currently remaining size based on caller's input */
711 CurrentSize
= *ElementSize
;
713 /* Iterate over every subje object */
714 for (i
= 0; i
< SubObjectCount
; i
++)
716 /* Set the currently remaining buffer space */
717 RequiredSize
= CurrentSize
;
719 /* Enumerate the inherited sub elements */
720 Status
= BiEnumerateSubElements(BcdHandle
,
722 BcdLibraryObjectList_InheritedObjects
,
727 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
729 /* Safely add the length of the sub elements */
730 Status
= RtlULongAdd(TotalSize
, RequiredSize
, &TotalSize
);
731 if (!NT_SUCCESS(Status
))
736 /* Add the sub elements to the total */
737 *ElementCount
+= SubElementCount
;
739 /* See if we have enough space*/
740 if (*ElementSize
>= TotalSize
)
742 /* Were there any subelements? */
745 /* Update to keep track of these new subelements */
746 CurrentSize
= *ElementSize
- TotalSize
;
748 /* Link the subelements into the chain */
749 PreviousElement
= Elements
;
750 PreviousElement
->NextEntry
=
751 (PBCD_PACKED_ELEMENT
)((ULONG_PTR
)Elements
+ TotalSize
);
752 Elements
= PreviousElement
->NextEntry
;
757 /* We're out of space */
761 else if ((Status
!= STATUS_NOT_FOUND
) &&
762 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
))
764 /* Some other fatal error, break out */
769 /* The sub element was not found, print a warning but keep going */
770 BlStatusPrint(L
"Ignoring missing BCD inherit object: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
771 (&SubObjectList
[i
])->Data1
,
772 (&SubObjectList
[i
])->Data2
,
773 (&SubObjectList
[i
])->Data3
,
774 (&SubObjectList
[i
])->Data4
[0],
775 (&SubObjectList
[i
])->Data4
[1],
776 (&SubObjectList
[i
])->Data4
[2],
777 (&SubObjectList
[i
])->Data4
[3],
778 (&SubObjectList
[i
])->Data4
[4],
779 (&SubObjectList
[i
])->Data4
[5],
780 (&SubObjectList
[i
])->Data4
[6],
781 (&SubObjectList
[i
])->Data4
[7],
782 (&SubObjectList
[i
])->Data4
[8]);
783 Status
= STATUS_SUCCESS
;
787 /* Terminate the last element, if one was left */
790 PreviousElement
->NextEntry
= NULL
;
793 /* Set failure code if we ran out of space */
794 if (*ElementSize
< TotalSize
)
796 Status
= STATUS_BUFFER_TOO_SMALL
;
799 /* Return final length and status */
800 *ElementSize
= TotalSize
;
805 BiEnumerateElements (
806 _In_ HANDLE BcdHandle
,
807 _In_ HANDLE ObjectHandle
,
808 _In_ ULONG RootElementType
,
810 _Out_opt_ PBCD_PACKED_ELEMENT Elements
,
811 _Inout_ PULONG ElementSize
,
812 _Out_ PULONG ElementCount
815 HANDLE ElementsHandle
, ElementHandle
;
816 ULONG TotalLength
, RegistryElementDataLength
, RemainingLength
;
819 PVOID ElementData
, SubObjectList
, RegistryElementData
;
820 BcdElementType ElementType
;
821 PBCD_PACKED_ELEMENT PreviousElement
, ElementsStart
;
822 ULONG SubElementCount
, SubKeyCount
, SubObjectCount
, ElementDataLength
;
829 /* Initialize all locals that are checked at the end*/
831 ElementsHandle
= NULL
;
832 ElementHandle
= NULL
;
834 RegistryElementData
= NULL
;
835 PreviousElement
= NULL
;
837 SubObjectList
= NULL
;
839 ElementDataLength
= 0;
842 ElementsStart
= Elements
;
844 /* Open the root object key's elements */
845 Status
= BiOpenKey(ObjectHandle
, L
"Elements", &ElementsHandle
);
846 if (!NT_SUCCESS(Status
))
851 /* Enumerate all elements */
852 Status
= BiEnumerateSubKeys(ElementsHandle
, &SubKeys
, &SubKeyCount
);
853 if (!NT_SUCCESS(Status
))
858 /* Iterate over each one */
859 for (i
= 0; i
< SubKeyCount
; i
++)
861 /* Open the element */
862 ElementName
= SubKeys
[i
];
863 Status
= BiOpenKey(ElementsHandle
, ElementName
, &ElementHandle
);
864 if (!NT_SUCCESS(Status
))
866 EfiPrintf(L
"ELEMENT ERROR: %lx\r\n", Status
);
871 /* The name of the element is its data type */
872 ElementType
.PackedValue
= wcstoul(SubKeys
[i
], NULL
, 16);
873 if (!(ElementType
.PackedValue
) || (ElementType
.PackedValue
== -1))
875 EfiPrintf(L
"Value invalid\r\n");
876 BiCloseKey(ElementHandle
);
877 ElementHandle
= NULL
;
881 /* Read the appropriate registry value type for this element */
882 Status
= BiGetRegistryValue(ElementHandle
,
884 BiConvertElementFormatToValueType(
886 &RegistryElementData
,
887 &RegistryElementDataLength
);
888 if (!NT_SUCCESS(Status
))
890 EfiPrintf(L
"Element invalid\r\n");
894 /* Now figure out how much space the converted element will need */
895 ElementDataLength
= 0;
896 Status
= BiConvertRegistryDataToElement(ObjectHandle
,
898 RegistryElementDataLength
,
902 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
907 /* Allocate a buffer big enough for the converted element */
908 ElementData
= BlMmAllocateHeap(ElementDataLength
);
911 Status
= STATUS_INSUFFICIENT_RESOURCES
;
915 /* And actually convert it this time around */
916 Status
= BiConvertRegistryDataToElement(ObjectHandle
,
918 RegistryElementDataLength
,
922 if (!NT_SUCCESS(Status
))
927 /* Safely add space for the packed element header */
928 Status
= RtlULongAdd(TotalLength
,
929 FIELD_OFFSET(BCD_PACKED_ELEMENT
, Data
),
931 if (!NT_SUCCESS(Status
))
936 /* Safely add space for the data of the element itself */
937 Status
= RtlULongAdd(TotalLength
, ElementDataLength
, &TotalLength
);
938 if (!NT_SUCCESS(Status
))
943 /* One more element */
946 /* See how much space we were given */
947 RemainingLength
= *ElementSize
;
948 if (RemainingLength
>= TotalLength
)
950 /* Set the next pointer */
951 Elements
->NextEntry
= (PBCD_PACKED_ELEMENT
)((ULONG_PTR
)ElementsStart
+ TotalLength
);
953 /* Fill this one out */
954 Elements
->RootType
.PackedValue
= RootElementType
;
955 Elements
->Version
= 1;
956 Elements
->Type
= ElementType
.PackedValue
;
957 Elements
->Size
= ElementDataLength
;
960 RtlCopyMemory(Elements
->Data
, ElementData
, ElementDataLength
);
961 RemainingLength
-= TotalLength
;
963 /* Move to the next element on the next pass */
964 PreviousElement
= Elements
;
965 Elements
= Elements
->NextEntry
;
969 /* We're out of space */
973 /* Are we enumerating devices, and is this a device? */
974 if ((Flags
& BCD_ENUMERATE_FLAG_DEVICES
) &&
975 (ElementType
.Format
== BCD_TYPE_DEVICE
))
977 /* Yep, so go inside to enumerate it */
978 Status
= BiEnumerateSubElements(BcdHandle
,
980 ElementType
.PackedValue
,
985 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
987 /* Safely add the length of the sub elements */
988 Status
= RtlULongAdd(TotalLength
,
991 if (!NT_SUCCESS(Status
))
996 /* Add the sub elements to the total */
997 *ElementCount
+= SubElementCount
;
999 /* See if we have enough space*/
1000 if (*ElementSize
>= TotalLength
)
1002 /* Were there any subelements? */
1003 if (SubElementCount
)
1005 /* Update to keep track of these new subelements */
1006 ElementDataLength
= *ElementSize
- TotalLength
;
1008 /* Link the subelements into the chain */
1009 PreviousElement
= Elements
;
1010 PreviousElement
->NextEntry
=
1011 (PBCD_PACKED_ELEMENT
)((ULONG_PTR
)ElementsStart
+
1013 Elements
= PreviousElement
->NextEntry
;
1018 /* We're out of space */
1019 ElementDataLength
= 0;
1022 else if ((Status
!= STATUS_NOT_FOUND
) &&
1023 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
))
1025 /* Fatal error trying to read the data, so fail */
1029 else if ((Flags
& BCD_ENUMERATE_FLAG_DEEP
) &&
1030 (ElementType
.PackedValue
== BcdLibraryObjectList_InheritedObjects
))
1032 /* Inherited objects are requsted, so allocate a buffer for them */
1033 SubObjectList
= BlMmAllocateHeap(ElementDataLength
);
1036 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1040 /* Copy the elements into the list. They are arrays of GUIDs */
1041 RtlCopyMemory(SubObjectList
, ElementData
, ElementDataLength
);
1042 SubObjectCount
= ElementDataLength
/ sizeof(GUID
);
1045 /* Free our local buffers */
1046 BlMmFreeHeap(ElementData
);
1047 BlMmFreeHeap(RegistryElementData
);
1049 RegistryElementData
= NULL
;
1052 BiCloseKey(ElementHandle
);
1053 ElementHandle
= NULL
;
1057 /* Did we end up here with a sub object list after successful loop parsing? */
1058 if ((i
!= 0) && (i
== SubKeyCount
) && (SubObjectList
))
1060 /* We will actually enumerate it now, at the end */
1061 Status
= BiEnumerateSubObjectElements(BcdHandle
,
1068 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
1070 /* Safely add the length of the sub elements */
1071 Status
= RtlULongAdd(TotalLength
, RemainingLength
, &TotalLength
);
1072 if ((NT_SUCCESS(Status
)) && (SubElementCount
))
1074 /* Add the sub elements to the total */
1075 *ElementCount
+= SubElementCount
;
1077 /* Don't touch PreviousElement anymore */
1078 PreviousElement
= NULL
;
1084 /* Free the sub object list, if any */
1087 BlMmFreeHeap(SubObjectList
);
1090 /* Free any local element data */
1093 BlMmFreeHeap(ElementData
);
1096 /* Free any local registry data */
1097 if (RegistryElementData
)
1099 BlMmFreeHeap(RegistryElementData
);
1102 /* Close the handle if still opened */
1105 BiCloseKey(ElementHandle
);
1108 /* Terminate the last element, if any */
1109 if (PreviousElement
)
1111 PreviousElement
->NextEntry
= NULL
;
1114 /* Close the root handle if still opened */
1117 BiCloseKey(ElementsHandle
);
1120 /* Set failure code if out of space */
1121 if (*ElementSize
< TotalLength
)
1123 Status
= STATUS_BUFFER_TOO_SMALL
;
1126 /* Other errors will send a notification error */
1127 if (!(NT_SUCCESS(Status
)) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
1129 BiNotifyEnumerationError(ObjectHandle
, ElementName
, Status
);
1132 /* Finally free the subkeys array */
1135 BlMmFreeHeap(SubKeys
);
1138 /* And return the required, final length and status */
1139 *ElementSize
= TotalLength
;
1144 BiAddStoreFromFile (
1145 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
1146 _Out_ PHANDLE StoreHandle
1150 HANDLE HiveHandle
, KeyHandle
;
1152 /* Load the specified hive */
1153 Status
= BiLoadHive(FilePath
, &HiveHandle
);
1154 if (!NT_SUCCESS(Status
))
1159 /* Open the description key to make sure this is really a BCD */
1160 Status
= BiOpenKey(HiveHandle
, L
"Description", &KeyHandle
);
1161 if (NT_SUCCESS(Status
))
1163 /* It is -- close the key as we don't need it */
1164 BiCloseKey(KeyHandle
);
1165 *StoreHandle
= HiveHandle
;
1169 /* Failure, drop a reference on the hive and close the key */
1170 BiDereferenceHive(HiveHandle
);
1171 BiCloseKey(HiveHandle
);
1174 /* Return the status */
1179 BiGetObjectDescription (
1180 _In_ HANDLE ObjectHandle
,
1181 _Out_ PBCD_OBJECT_DESCRIPTION Description
1185 HANDLE DescriptionHandle
;
1189 /* Initialize locals */
1191 DescriptionHandle
= NULL
;
1193 /* Open the description key */
1194 Status
= BiOpenKey(ObjectHandle
, L
"Description", &DescriptionHandle
);
1195 if (NT_SUCCESS(Status
))
1198 Description
->Valid
= TRUE
;
1202 Status
= BiGetRegistryValue(DescriptionHandle
,
1207 if (NT_SUCCESS(Status
))
1209 /* Make sure it's the length we expected it to be */
1210 if (Length
== sizeof(Data
))
1212 /* Return the type that is stored there */
1213 Description
->Type
= *Data
;
1217 /* Invalid type value */
1218 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1223 /* Did we have a handle open? */
1224 if (DescriptionHandle
)
1227 BiCloseKey(DescriptionHandle
);
1230 /* Did we have data allocated? */
1237 /* Return back to caller */
1242 BcdEnumerateAndUnpackElements (
1243 _In_ HANDLE BcdHandle
,
1244 _In_ HANDLE ObjectHandle
,
1245 _Out_opt_ PBCD_ELEMENT Elements
,
1246 _Inout_ PULONG ElementSize
,
1247 _Out_ PULONG ElementCount
1250 PVOID LocalElements
;
1252 ULONG LocalElementCount
, LocalElementSize
;
1254 /* Make sure required parameters are there */
1255 if (!(ElementSize
) || !(ElementCount
) || ((Elements
) && (!*ElementSize
)))
1257 return STATUS_INVALID_PARAMETER
;
1260 /* Set initial count to zero */
1263 /* Do the initial enumeration to figure out the size required */
1264 LocalElementSize
= 0;
1265 LocalElementCount
= 0;
1266 Status
= BiEnumerateElements(BcdHandle
,
1269 BCD_ENUMERATE_FLAG_IN_ORDER
|
1270 BCD_ENUMERATE_FLAG_DEVICES
|
1271 BCD_ENUMERATE_FLAG_DEEP
,
1274 &LocalElementCount
);
1275 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1280 /* Now allocate a buffer large enough to hold them */
1281 LocalElements
= BlMmAllocateHeap(LocalElementSize
);
1284 return STATUS_INSUFFICIENT_RESOURCES
;
1287 /* Zero out the array and do the real enumeration this time around */
1288 RtlZeroMemory(LocalElements
, LocalElementSize
);
1289 Status
= BiEnumerateElements(BcdHandle
,
1292 BCD_ENUMERATE_FLAG_IN_ORDER
|
1293 BCD_ENUMERATE_FLAG_DEVICES
|
1294 BCD_ENUMERATE_FLAG_DEEP
,
1297 &LocalElementCount
);
1298 if (!NT_SUCCESS(Status
))
1303 /* Now we know the real count */
1304 *ElementCount
= LocalElementCount
;
1306 /* Now unpack the data */
1307 Status
= BiConvertBcdElements(LocalElements
,
1310 &LocalElementCount
);
1311 if (NT_SUCCESS(Status
))
1313 /* Not all elements may have been converted */
1314 *ElementCount
= LocalElementCount
;
1317 /* Free the local (unpacked) buffer and return status */
1318 BlMmFreeHeap(LocalElements
);
1323 BcdOpenStoreFromFile (
1324 _In_ PUNICODE_STRING FileName
,
1325 _In_ PHANDLE BcdHandle
1329 PBL_FILE_PATH_DESCRIPTOR FilePath
;
1333 /* Assume failure */
1336 /* Allocate a path descriptor */
1337 Length
= FileName
->Length
+ sizeof(*FilePath
);
1338 FilePath
= BlMmAllocateHeap(Length
);
1341 return STATUS_NO_MEMORY
;
1345 FilePath
->Version
= 1;
1346 FilePath
->PathType
= InternalPath
;
1347 FilePath
->Length
= Length
;
1349 /* Copy the name and NULL-terminate it */
1350 RtlCopyMemory(FilePath
->Path
, FileName
->Buffer
, Length
);
1351 FilePath
->Path
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1354 Status
= BiAddStoreFromFile(FilePath
, &LocalHandle
);
1355 if (NT_SUCCESS(Status
))
1357 /* Return the handle on success */
1358 *BcdHandle
= LocalHandle
;
1361 /* Free the descriptor and return the status */
1362 BlMmFreeHeap(FilePath
);