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 *****************************************************************/
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
;
155 ULONG StringLength
, CopyLength
;
156 //PGUID AppIdentifier;
158 /* Make sure this is a BCD_STRING */
159 if ((Type
& 0xF000000) != 0x2000000)
161 return STATUS_INVALID_PARAMETER
;
164 /* Return the data */
165 Option
= MiscGetBootOption(List
, Type
);
168 /* Extract the string */
169 String
= (PWCHAR
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
170 Status
= STATUS_SUCCESS
;
174 /* No string is present */
176 Status
= STATUS_NOT_FOUND
;
179 /* Compute the data size */
180 StringLength
= Option
->DataSize
/ sizeof(WCHAR
);
183 /* Filter out SecureBoot Options */
184 AppIdentifier
= BlGetApplicationIdentifier();
185 Status
= BlpBootOptionCallbackString(AppIdentifier
, Type
, String
, StringLength
, &String
, &StringLength
);
188 /* Check if we have space for one more character */
189 CopyLength
= StringLength
+ 1;
190 if (CopyLength
< StringLength
)
192 /* Nope, we'll overflow */
194 Status
= STATUS_INTEGER_OVERFLOW
;
198 if (NT_SUCCESS(Status
))
200 /* Check if it's safe to multiply by two */
201 if ((CopyLength
* sizeof(WCHAR
)) > 0xFFFFFFFF)
205 Status
= STATUS_INTEGER_OVERFLOW
;
209 /* We're good, do the multiplication */
210 Status
= STATUS_SUCCESS
;
211 CopyLength
*= sizeof(WCHAR
);
214 /* Allocate a copy for the string */
215 if (NT_SUCCESS(Status
))
217 StringCopy
= BlMmAllocateHeap(CopyLength
);
220 /* NULL-terminate it */
221 RtlCopyMemory(StringCopy
,
223 CopyLength
- sizeof(UNICODE_NULL
));
224 StringCopy
[CopyLength
] = UNICODE_NULL
;
226 Status
= STATUS_SUCCESS
;
230 /* No memory, fail */
231 Status
= STATUS_NO_MEMORY
;
241 BlGetBootOptionDevice (
242 _In_ PBL_BCD_OPTION List
,
244 _Out_ PBL_DEVICE_DESCRIPTOR
* Value
,
245 _In_opt_ PBL_BCD_OPTION
* ExtraOptions
249 PBL_BCD_OPTION Option
, ListData
, ListCopy
, SecureListData
;
250 PBCD_DEVICE_OPTION BcdDevice
;
251 ULONG DeviceSize
, ListOffset
, ListSize
;
252 PBL_DEVICE_DESCRIPTOR DeviceDescriptor
, SecureDescriptor
;
253 //PGUID AppIdentifier;
255 /* Make sure this is a BCD_DEVICE */
256 if ((Type
& 0xF000000) != 0x1000000)
258 return STATUS_INVALID_PARAMETER
;
261 /* Return the data */
262 Option
= MiscGetBootOption(List
, Type
);
265 /* Set failure if no data exists */
266 Status
= STATUS_NOT_FOUND
;
270 /* Otherwise, read the size of the BCD device encoded */
271 BcdDevice
= (PBCD_DEVICE_OPTION
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
272 DeviceSize
= BcdDevice
->DeviceDescriptor
.Size
;
274 /* Allocate a buffer to copy it into */
275 DeviceDescriptor
= BlMmAllocateHeap(DeviceSize
);
276 if (!DeviceDescriptor
)
278 return STATUS_NO_MEMORY
;
281 /* Copy it into that buffer */
282 RtlCopyMemory(DeviceDescriptor
, &BcdDevice
->DeviceDescriptor
, DeviceSize
);
283 Status
= STATUS_SUCCESS
;
286 /* Check if extra options were requested */
289 /* See where they are */
290 ListOffset
= Option
->ListOffset
;
293 /* See how big they are */
294 ListData
= (PBL_BCD_OPTION
)((ULONG_PTR
)Option
+ ListOffset
);
295 ListSize
= BlGetBootOptionListSize(ListData
);
297 /* Allocate a buffer to hold them into */
298 ListCopy
= BlMmAllocateHeap(ListSize
);
301 Status
= STATUS_NO_MEMORY
;
305 /* Copy them in there */
306 RtlCopyMemory(ListCopy
, ListData
, ListSize
);
311 /* Filter out SecureBoot Options */
312 AppIdentifier
= BlGetApplicationIdentifier();
313 if (BlpBootOptionCallbacks
)
315 DeviceCallback
= BlpBootOptionCallbacks
->Device
;
318 Status
= DeviceCallback(BlpBootOptionCallbackCookie
,
328 /* No secure boot, so the secure descriptors are the standard ones */
329 SecureDescriptor
= DeviceDescriptor
;
330 SecureListData
= ListCopy
;
333 /* Check if the data was read correctly */
334 if (NT_SUCCESS(Status
))
336 /* Check if we had a new descriptor after filtering */
337 if (SecureDescriptor
!= DeviceDescriptor
)
339 /* Yep -- if we had an old one, free it */
340 if (DeviceDescriptor
)
342 BlMmFreeHeap(DeviceDescriptor
);
346 /* Check if we had a new list after filtering */
347 if (SecureListData
!= ListCopy
)
349 /* Yep -- if we had an old list, free it */
352 BlMmFreeHeap(ListCopy
);
356 /* Finally, check if the caller wanted extra options */
359 /* Yep -- so pass the caller our copy */
360 *ExtraOptions
= ListCopy
;
364 /* Caller always wants data back, so pass them our copy */
365 *Value
= DeviceDescriptor
;
366 DeviceDescriptor
= NULL
;
370 /* On the failure path, if these buffers are active, we should free them */
373 BlMmFreeHeap(ListCopy
);
375 if (DeviceDescriptor
)
377 BlMmFreeHeap(DeviceDescriptor
);
385 BlGetBootOptionInteger (
386 _In_ PBL_BCD_OPTION List
,
388 _Out_ PULONGLONG Value
392 PBL_BCD_OPTION Option
;
393 //PGUID AppIdentifier;
395 /* Make sure this is a BCD_INTEGER */
396 if ((Type
& 0xF000000) != 0x5000000)
398 return STATUS_INVALID_PARAMETER
;
401 /* Return the data */
402 Option
= MiscGetBootOption(List
, Type
);
405 *Value
= *(PULONGLONG
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
409 /* Filter out SecureBoot Options */
410 AppIdentifier
= BlGetApplicationIdentifier();
411 Status
= BlpBootOptionCallbackULongLong(AppIdentifier
, Type
, Value
);
414 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
420 BlGetBootOptionBoolean (
421 _In_ PBL_BCD_OPTION List
,
427 PBL_BCD_OPTION Option
;
428 //PGUID AppIdentifier;
430 /* Make sure this is a BCD_BOOLEAN */
431 if ((Type
& 0xF000000) != 0x6000000)
433 return STATUS_INVALID_PARAMETER
;
436 /* Return the data */
437 Option
= MiscGetBootOption(List
, Type
);
440 *Value
= *(PBOOLEAN
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
444 /* Filter out SecureBoot Options */
445 AppIdentifier
= BlGetApplicationIdentifier();
446 Status
= BlpBootOptionCallbackBoolean(AppIdentifier
, Type
, Value
);
449 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
454 #define BI_FLUSH_HIVE 0x01
456 typedef struct _BI_KEY_HIVE
459 PBL_FILE_PATH_DESCRIPTOR FilePath
;
463 } BI_KEY_HIVE
, *PBI_KEY_HIVE
;
465 typedef struct _BI_KEY_OBJECT
467 PBI_KEY_HIVE KeyHive
;
468 PCM_KEY_NODE KeyNode
;
471 } BI_KEY_OBJECT
, *PBI_KEY_OBJECT
;
481 UNREFERENCED_PARAMETER(Paged
);
482 UNREFERENCED_PARAMETER(Tag
);
484 /* Call the heap allocator */
485 return BlMmAllocateHeap(Size
);
495 UNREFERENCED_PARAMETER(Quota
);
497 /* Call the heap allocator */
504 _In_ HANDLE KeyHandle
507 PBI_KEY_OBJECT KeyObject
;
509 /* Get the key object */
510 KeyObject
= (PBI_KEY_OBJECT
)KeyHandle
;
512 /* Drop a reference on the parent hive */
513 --KeyObject
->KeyHive
->ReferenceCount
;
518 _In_ HANDLE KeyHandle
521 /* Not yet implemented */
522 EfiPrintf(L
"NO reg flush\r\n");
528 _In_ HANDLE KeyHandle
531 PBI_KEY_HIVE KeyHive
;
532 PBI_KEY_OBJECT KeyObject
;
534 /* Get the key object and hive */
535 KeyObject
= (PBI_KEY_OBJECT
)KeyHandle
;
536 KeyHive
= KeyObject
->KeyHive
;
538 /* Check if we have a hive, or name, or key node */
539 if ((KeyHive
) || (KeyObject
->KeyNode
) || (KeyObject
->KeyName
))
541 /* Drop a reference, see if it's the last one */
542 BiDereferenceHive(KeyHandle
);
543 if (!KeyHive
->ReferenceCount
)
545 /* Check if we should flush it */
546 if (KeyHive
->Flags
& BI_FLUSH_HIVE
)
548 BiFlushHive(KeyHandle
);
552 //MmPapFreePages(KeyHive->ImageBase, 1);
553 EfiPrintf(L
"Leaking hive memory\r\n");
555 /* Free the hive and hive path */
556 BlMmFreeHeap(KeyHive
->FilePath
);
557 BlMmFreeHeap(KeyHive
);
560 /* Check if a key name is present */
561 if (KeyObject
->KeyName
)
564 BlMmFreeHeap(KeyObject
->KeyName
);
568 /* Free the object */
569 BlMmFreeHeap(KeyObject
);
574 _In_ HANDLE ParentHandle
,
579 PBI_KEY_OBJECT ParentKey
, NewKey
;
580 PBI_KEY_HIVE ParentHive
;
582 ULONG NameLength
, SubNameLength
, NameBytes
;
583 PWCHAR NameStart
, NameBuffer
;
584 UNICODE_STRING KeyString
;
587 PCM_KEY_NODE ParentNode
;
589 /* Convert from a handle to our key object */
590 ParentKey
= (PBI_KEY_OBJECT
)ParentHandle
;
592 /* Extract the hive and node information */
593 ParentHive
= ParentKey
->KeyHive
;
594 ParentNode
= ParentKey
->KeyNode
;
595 Hive
= &ParentKey
->KeyHive
->Hive
.Hive
;
597 /* Initialize variables */
599 Status
= STATUS_SUCCESS
;
602 /* Loop as long as there's still portions of the key name in play */
603 NameLength
= wcslen(KeyName
);
606 /* Find the first path separator */
607 NameStart
= wcschr(KeyName
, OBJ_NAME_PATH_SEPARATOR
);
610 /* Look only at the key before the separator */
611 SubNameLength
= NameStart
- KeyName
;
616 /* No path separator, this is the final leaf key */
617 SubNameLength
= NameLength
;
620 /* Free the name buffer from the previous pass if needed */
623 BlMmFreeHeap(NameBuffer
);
626 /* Allocate a buffer to hold the name of this specific subkey only */
627 NameBytes
= SubNameLength
* sizeof(WCHAR
);
628 NameBuffer
= BlMmAllocateHeap(NameBytes
+ sizeof(UNICODE_NULL
));
631 Status
= STATUS_NO_MEMORY
;
635 /* Copy and null-terminate the name of the subkey */
636 RtlCopyMemory(NameBuffer
, KeyName
, NameBytes
);
637 NameBuffer
[SubNameLength
] = UNICODE_NULL
;
639 /* Convert it into a UNICODE_STRING and try to find it */
640 RtlInitUnicodeString(&KeyString
, NameBuffer
);
641 KeyCell
= CmpFindSubKeyByName(Hive
, ParentNode
, &KeyString
);
642 if (KeyCell
== HCELL_NIL
)
644 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
648 /* We found it -- get the key node out of it */
649 ParentNode
= (PCM_KEY_NODE
)Hive
->GetCellRoutine(Hive
, KeyCell
);
652 Status
= STATUS_REGISTRY_CORRUPT
;
656 /* Update the key name to the next remaining path element */
660 /* Update the length to the remainder of the path */
661 NameLength
+= -1 - SubNameLength
;
665 /* There's nothing left, this was the leaf key */
670 /* Allocate a key object */
671 NewKey
= BlMmAllocateHeap(sizeof(*NewKey
));
674 /* Bail out if we had no memory for it */
675 Status
= STATUS_NO_MEMORY
;
679 /* Fill out the key object data */
680 NewKey
->KeyNode
= ParentNode
;
681 NewKey
->KeyHive
= ParentHive
;
682 NewKey
->KeyName
= NameBuffer
;
683 NewKey
->KeyCell
= KeyCell
;
685 /* Add a reference to the hive */
686 ++ParentHive
->ReferenceCount
;
688 /* Return the object back to the caller */
692 /* If we had a name buffer, free it */
695 BlMmFreeHeap(NameBuffer
);
698 /* Return status of the open operation */
704 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
705 _Out_ PHANDLE HiveHandle
709 EfiPrintf(L
"Loading a hive is not yet implemented\r\n");
711 return STATUS_NOT_IMPLEMENTED
;
716 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
717 _Out_ PHANDLE StoreHandle
721 HANDLE HiveHandle
, KeyHandle
;
723 /* Load the specified hive */
724 Status
= BiLoadHive(FilePath
, &HiveHandle
);
725 if (!NT_SUCCESS(Status
))
730 /* Open the description key to make sure this is really a BCD */
731 Status
= BiOpenKey(HiveHandle
, L
"Description", &KeyHandle
);
732 if (NT_SUCCESS(Status
))
734 /* It is -- close the key as we don't need it */
735 BiCloseKey(KeyHandle
);
736 *StoreHandle
= HiveHandle
;
740 /* Failure, drop a reference on the hive and close the key */
741 BiDereferenceHive(HiveHandle
);
742 BiCloseKey(HiveHandle
);
745 /* Return the status */
750 BcdOpenStoreFromFile (
751 _In_ PUNICODE_STRING FileName
,
752 _In_ PHANDLE StoreHandle
756 PBL_FILE_PATH_DESCRIPTOR FilePath
;
762 EfiPrintf(L
"Opening BCD store: %wZ\n", FileName
);
764 /* Allocate a path descriptor */
765 Length
= FileName
->Length
+ sizeof(*FilePath
);
766 FilePath
= BlMmAllocateHeap(Length
);
769 return STATUS_NO_MEMORY
;
773 FilePath
->Version
= 1;
774 FilePath
->PathType
= InternalPath
;
775 FilePath
->Length
= Length
;
777 /* Copy the name and NULL-terminate it */
778 RtlCopyMemory(FilePath
->Path
, FileName
->Buffer
, Length
);
779 FilePath
->Path
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
782 Status
= BiAddStoreFromFile(FilePath
, &LocalHandle
);
783 if (NT_SUCCESS(Status
))
785 /* Return the handle on success */
786 *StoreHandle
= LocalHandle
;
789 /* Free the descriptor and return the status */
790 BlMmFreeHeap(FilePath
);