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 SIZE_T 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 Status
= STATUS_SUCCESS
;
786 /* Terminate the last element, if one was left */
789 PreviousElement
->NextEntry
= NULL
;
792 /* Set failure code if we ran out of space */
793 if (*ElementSize
< TotalSize
)
795 Status
= STATUS_BUFFER_TOO_SMALL
;
798 /* Return final length and status */
799 *ElementSize
= TotalSize
;
804 BiEnumerateElements (
805 _In_ HANDLE BcdHandle
,
806 _In_ HANDLE ObjectHandle
,
807 _In_ ULONG RootElementType
,
809 _Out_opt_ PBCD_PACKED_ELEMENT Elements
,
810 _Inout_ PULONG ElementSize
,
811 _Out_ PULONG ElementCount
814 HANDLE ElementsHandle
, ElementHandle
;
815 ULONG TotalLength
, RegistryElementDataLength
, RemainingLength
;
818 PVOID ElementData
, SubObjectList
, RegistryElementData
;
819 BcdElementType ElementType
;
820 PBCD_PACKED_ELEMENT PreviousElement
, ElementsStart
;
821 ULONG SubElementCount
, SubKeyCount
, SubObjectCount
, ElementDataLength
;
828 /* Initialize all locals that are checked at the end*/
830 ElementsHandle
= NULL
;
831 ElementHandle
= NULL
;
833 RegistryElementData
= NULL
;
834 PreviousElement
= NULL
;
836 SubObjectList
= NULL
;
838 ElementDataLength
= 0;
841 ElementsStart
= Elements
;
843 /* Open the root object key's elements */
844 Status
= BiOpenKey(ObjectHandle
, L
"Elements", &ElementsHandle
);
845 if (!NT_SUCCESS(Status
))
850 /* Enumerate all elements */
851 Status
= BiEnumerateSubKeys(ElementsHandle
, &SubKeys
, &SubKeyCount
);
852 if (!NT_SUCCESS(Status
))
857 /* Iterate over each one */
858 for (i
= 0; i
< SubKeyCount
; i
++)
860 /* Open the element */
861 ElementName
= SubKeys
[i
];
862 Status
= BiOpenKey(ElementsHandle
, ElementName
, &ElementHandle
);
863 if (!NT_SUCCESS(Status
))
865 EfiPrintf(L
"ELEMENT ERROR: %lx\r\n", Status
);
870 /* The name of the element is its data type */
871 ElementType
.PackedValue
= wcstoul(SubKeys
[i
], NULL
, 16);
872 if (!(ElementType
.PackedValue
) || (ElementType
.PackedValue
== -1))
874 EfiPrintf(L
"Value invalid\r\n");
875 BiCloseKey(ElementHandle
);
876 ElementHandle
= NULL
;
880 /* Read the appropriate registry value type for this element */
881 Status
= BiGetRegistryValue(ElementHandle
,
883 BiConvertElementFormatToValueType(
885 &RegistryElementData
,
886 &RegistryElementDataLength
);
887 if (!NT_SUCCESS(Status
))
889 EfiPrintf(L
"Element invalid\r\n");
893 /* Now figure out how much space the converted element will need */
894 ElementDataLength
= 0;
895 Status
= BiConvertRegistryDataToElement(ObjectHandle
,
897 RegistryElementDataLength
,
901 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
906 /* Allocate a buffer big enough for the converted element */
907 ElementData
= BlMmAllocateHeap(ElementDataLength
);
910 Status
= STATUS_INSUFFICIENT_RESOURCES
;
914 /* And actually convert it this time around */
915 Status
= BiConvertRegistryDataToElement(ObjectHandle
,
917 RegistryElementDataLength
,
921 if (!NT_SUCCESS(Status
))
926 /* Safely add space for the packed element header */
927 Status
= RtlULongAdd(TotalLength
,
928 FIELD_OFFSET(BCD_PACKED_ELEMENT
, Data
),
930 if (!NT_SUCCESS(Status
))
935 /* Safely add space for the data of the element itself */
936 Status
= RtlULongAdd(TotalLength
, ElementDataLength
, &TotalLength
);
937 if (!NT_SUCCESS(Status
))
942 /* One more element */
945 /* See how much space we were given */
946 RemainingLength
= *ElementSize
;
947 if (RemainingLength
>= TotalLength
)
949 /* Set the next pointer */
950 Elements
->NextEntry
= (PBCD_PACKED_ELEMENT
)((ULONG_PTR
)ElementsStart
+ TotalLength
);
952 /* Fill this one out */
953 Elements
->RootType
.PackedValue
= RootElementType
;
954 Elements
->Version
= 1;
955 Elements
->Type
= ElementType
.PackedValue
;
956 Elements
->Size
= ElementDataLength
;
959 RtlCopyMemory(Elements
->Data
, ElementData
, ElementDataLength
);
960 RemainingLength
-= TotalLength
;
962 /* Move to the next element on the next pass */
963 PreviousElement
= Elements
;
964 Elements
= Elements
->NextEntry
;
968 /* We're out of space */
972 /* Are we enumerating devices, and is this a device? */
973 if ((Flags
& BCD_ENUMERATE_FLAG_DEVICES
) &&
974 (ElementType
.Format
== BCD_TYPE_DEVICE
))
976 /* Yep, so go inside to enumerate it */
977 Status
= BiEnumerateSubElements(BcdHandle
,
979 ElementType
.PackedValue
,
984 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
986 /* Safely add the length of the sub elements */
987 Status
= RtlULongAdd(TotalLength
,
990 if (!NT_SUCCESS(Status
))
995 /* Add the sub elements to the total */
996 *ElementCount
+= SubElementCount
;
998 /* See if we have enough space*/
999 if (*ElementSize
>= TotalLength
)
1001 /* Were there any subelements? */
1002 if (SubElementCount
)
1004 /* Update to keep track of these new subelements */
1005 ElementDataLength
= *ElementSize
- TotalLength
;
1007 /* Link the subelements into the chain */
1008 PreviousElement
= Elements
;
1009 PreviousElement
->NextEntry
=
1010 (PBCD_PACKED_ELEMENT
)((ULONG_PTR
)ElementsStart
+
1012 Elements
= PreviousElement
->NextEntry
;
1017 /* We're out of space */
1018 ElementDataLength
= 0;
1021 else if ((Status
!= STATUS_NOT_FOUND
) &&
1022 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
))
1024 /* Fatal error trying to read the data, so fail */
1028 else if ((Flags
& BCD_ENUMERATE_FLAG_DEEP
) &&
1029 (ElementType
.PackedValue
== BcdLibraryObjectList_InheritedObjects
))
1031 /* Inherited objects are requested, so allocate a buffer for them */
1032 SubObjectList
= BlMmAllocateHeap(ElementDataLength
);
1035 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1039 /* Copy the elements into the list. They are arrays of GUIDs */
1040 RtlCopyMemory(SubObjectList
, ElementData
, ElementDataLength
);
1041 SubObjectCount
= ElementDataLength
/ sizeof(GUID
);
1044 /* Free our local buffers */
1045 BlMmFreeHeap(ElementData
);
1046 BlMmFreeHeap(RegistryElementData
);
1048 RegistryElementData
= NULL
;
1051 BiCloseKey(ElementHandle
);
1052 ElementHandle
= NULL
;
1056 /* Did we end up here with a sub object list after successful loop parsing? */
1057 if ((i
!= 0) && (i
== SubKeyCount
) && (SubObjectList
))
1059 /* We will actually enumerate it now, at the end */
1060 Status
= BiEnumerateSubObjectElements(BcdHandle
,
1067 if ((NT_SUCCESS(Status
)) || (Status
== STATUS_BUFFER_TOO_SMALL
))
1069 /* Safely add the length of the sub elements */
1070 Status
= RtlULongAdd(TotalLength
, RemainingLength
, &TotalLength
);
1071 if ((NT_SUCCESS(Status
)) && (SubElementCount
))
1073 /* Add the sub elements to the total */
1074 *ElementCount
+= SubElementCount
;
1076 /* Don't touch PreviousElement anymore */
1077 PreviousElement
= NULL
;
1083 /* Free the sub object list, if any */
1086 BlMmFreeHeap(SubObjectList
);
1089 /* Free any local element data */
1092 BlMmFreeHeap(ElementData
);
1095 /* Free any local registry data */
1096 if (RegistryElementData
)
1098 BlMmFreeHeap(RegistryElementData
);
1101 /* Close the handle if still opened */
1104 BiCloseKey(ElementHandle
);
1107 /* Terminate the last element, if any */
1108 if (PreviousElement
)
1110 PreviousElement
->NextEntry
= NULL
;
1113 /* Close the root handle if still opened */
1116 BiCloseKey(ElementsHandle
);
1119 /* Set failure code if out of space */
1120 if (*ElementSize
< TotalLength
)
1122 Status
= STATUS_BUFFER_TOO_SMALL
;
1125 /* Other errors will send a notification error */
1126 if (!(NT_SUCCESS(Status
)) && (Status
!= STATUS_BUFFER_TOO_SMALL
))
1128 BiNotifyEnumerationError(ObjectHandle
, ElementName
, Status
);
1131 /* Finally free the subkeys array */
1134 BlMmFreeHeap(SubKeys
);
1137 /* And return the required, final length and status */
1138 *ElementSize
= TotalLength
;
1143 BiAddStoreFromFile (
1144 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
1145 _Out_ PHANDLE StoreHandle
1149 HANDLE HiveHandle
, KeyHandle
;
1151 /* Load the specified hive */
1152 Status
= BiLoadHive(FilePath
, &HiveHandle
);
1153 if (!NT_SUCCESS(Status
))
1158 /* Open the description key to make sure this is really a BCD */
1159 Status
= BiOpenKey(HiveHandle
, L
"Description", &KeyHandle
);
1160 if (NT_SUCCESS(Status
))
1162 /* It is -- close the key as we don't need it */
1163 BiCloseKey(KeyHandle
);
1164 *StoreHandle
= HiveHandle
;
1168 /* Failure, drop a reference on the hive and close the key */
1169 BiDereferenceHive(HiveHandle
);
1170 BiCloseKey(HiveHandle
);
1173 /* Return the status */
1178 BiGetObjectDescription (
1179 _In_ HANDLE ObjectHandle
,
1180 _Out_ PBCD_OBJECT_DESCRIPTION Description
1184 HANDLE DescriptionHandle
;
1188 /* Initialize locals */
1190 DescriptionHandle
= NULL
;
1192 /* Open the description key */
1193 Status
= BiOpenKey(ObjectHandle
, L
"Description", &DescriptionHandle
);
1194 if (NT_SUCCESS(Status
))
1197 Description
->Valid
= TRUE
;
1201 Status
= BiGetRegistryValue(DescriptionHandle
,
1206 if (NT_SUCCESS(Status
))
1208 /* Make sure it's the length we expected it to be */
1209 if (Length
== sizeof(Data
))
1211 /* Return the type that is stored there */
1212 Description
->Type
= *Data
;
1216 /* Invalid type value */
1217 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1222 /* Did we have a handle open? */
1223 if (DescriptionHandle
)
1226 BiCloseKey(DescriptionHandle
);
1229 /* Did we have data allocated? */
1236 /* Return back to caller */
1241 BcdEnumerateAndUnpackElements (
1242 _In_ HANDLE BcdHandle
,
1243 _In_ HANDLE ObjectHandle
,
1244 _Out_opt_ PBCD_ELEMENT Elements
,
1245 _Inout_ PULONG ElementSize
,
1246 _Out_ PULONG ElementCount
1249 PVOID LocalElements
;
1251 ULONG LocalElementCount
, LocalElementSize
;
1253 /* Make sure required parameters are there */
1254 if (!(ElementSize
) || !(ElementCount
) || ((Elements
) && (!*ElementSize
)))
1256 return STATUS_INVALID_PARAMETER
;
1259 /* Set initial count to zero */
1262 /* Do the initial enumeration to figure out the size required */
1263 LocalElementSize
= 0;
1264 LocalElementCount
= 0;
1265 Status
= BiEnumerateElements(BcdHandle
,
1268 BCD_ENUMERATE_FLAG_IN_ORDER
|
1269 BCD_ENUMERATE_FLAG_DEVICES
|
1270 BCD_ENUMERATE_FLAG_DEEP
,
1273 &LocalElementCount
);
1274 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1279 /* Now allocate a buffer large enough to hold them */
1280 LocalElements
= BlMmAllocateHeap(LocalElementSize
);
1283 return STATUS_INSUFFICIENT_RESOURCES
;
1286 /* Zero out the array and do the real enumeration this time around */
1287 RtlZeroMemory(LocalElements
, LocalElementSize
);
1288 Status
= BiEnumerateElements(BcdHandle
,
1291 BCD_ENUMERATE_FLAG_IN_ORDER
|
1292 BCD_ENUMERATE_FLAG_DEVICES
|
1293 BCD_ENUMERATE_FLAG_DEEP
,
1296 &LocalElementCount
);
1297 if (!NT_SUCCESS(Status
))
1302 /* Now we know the real count */
1303 *ElementCount
= LocalElementCount
;
1305 /* Now unpack the data */
1306 Status
= BiConvertBcdElements(LocalElements
,
1309 &LocalElementCount
);
1310 if (NT_SUCCESS(Status
))
1312 /* Not all elements may have been converted */
1313 *ElementCount
= LocalElementCount
;
1316 /* Free the local (unpacked) buffer and return status */
1317 BlMmFreeHeap(LocalElements
);
1322 BcdOpenStoreFromFile (
1323 _In_ PUNICODE_STRING FileName
,
1324 _In_ PHANDLE BcdHandle
1328 PBL_FILE_PATH_DESCRIPTOR FilePath
;
1332 /* Assume failure */
1335 /* Allocate a path descriptor */
1336 Length
= FileName
->Length
+ sizeof(*FilePath
);
1337 FilePath
= BlMmAllocateHeap(Length
);
1340 return STATUS_NO_MEMORY
;
1344 FilePath
->Version
= 1;
1345 FilePath
->PathType
= InternalPath
;
1346 FilePath
->Length
= Length
;
1348 /* Copy the name and NULL-terminate it */
1349 RtlCopyMemory(FilePath
->Path
, FileName
->Buffer
, Length
);
1350 FilePath
->Path
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1353 Status
= BiAddStoreFromFile(FilePath
, &LocalHandle
);
1354 if (NT_SUCCESS(Status
))
1356 /* Return the handle on success */
1357 *BcdHandle
= LocalHandle
;
1360 /* Free the descriptor and return the status */
1361 BlMmFreeHeap(FilePath
);