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 ******************************************************************/
13 /* FUNCTIONS *****************************************************************/
17 _In_ PBL_BCD_OPTION List
,
21 ULONG_PTR NextOption
= 0, ListOption
;
22 PBL_BCD_OPTION Option
;
24 /* No options, bail out */
30 /* Loop while we find an option */
33 /* Get the next option and see if it matches the type */
34 Option
= (PBL_BCD_OPTION
)((ULONG_PTR
)List
+ NextOption
);
35 if ((Option
->Type
== Type
) && !(Option
->Empty
))
40 /* Store the offset of the next option */
41 NextOption
= Option
->NextEntryOffset
;
43 /* Failed to match. Check for list options */
44 ListOption
= Option
->ListOffset
;
47 /* Try to get a match in the associated option */
48 Option
= MiscGetBootOption((PBL_BCD_OPTION
)((ULONG_PTR
)Option
+
52 /* Found one, return it */
60 /* We found the option, return it */
67 * @name BlGetBootOptionListSize
69 * The BlGetBootOptionListSize routine
72 * UEFI Image Handle for the current loaded application.
74 * @return Size of the BCD option
78 BlGetBootOptionListSize (
79 _In_ PBL_BCD_OPTION BcdOption
82 ULONG Size
= 0, NextOffset
= 0;
83 PBL_BCD_OPTION NextOption
;
85 /* Loop all the options*/
88 /* Move to the next one */
89 NextOption
= (PBL_BCD_OPTION
)((ULONG_PTR
)BcdOption
+ NextOffset
);
91 /* Compute the size of the next one */
92 Size
+= BlGetBootOptionSize(NextOption
);
94 /* Update the offset */
95 NextOffset
= NextOption
->NextEntryOffset
;
96 } while (NextOffset
!= 0);
98 /* Return final computed size */
103 * @name BlGetBootOptionSize
105 * The BlGetBootOptionSize routine
108 * UEFI Image Handle for the current loaded application.
110 * @return Size of the BCD option
114 BlGetBootOptionSize (
115 _In_ PBL_BCD_OPTION BcdOption
120 /* Check if there's any data */
121 if (BcdOption
->DataOffset
!= 0)
123 /* Add the size of the data */
124 Size
= BcdOption
->DataOffset
+ BcdOption
->DataSize
;
128 /* No data, just the structure itself */
129 Size
= sizeof(*BcdOption
);
132 /* Any associated options? */
133 Offset
= BcdOption
->ListOffset
;
136 /* Go get those too */
137 Size
+= BlGetBootOptionListSize((PVOID
)((ULONG_PTR
)BcdOption
+ Offset
));
140 /* Return the final size */
145 BlGetBootOptionString (
146 _In_ PBL_BCD_OPTION List
,
152 PBL_BCD_OPTION Option
;
153 PWCHAR String
, StringCopy
;
154 ULONG StringLength
, CopyLength
;
155 //PGUID AppIdentifier;
157 /* Make sure this is a BCD_STRING */
158 if ((Type
& 0xF000000) != 0x2000000)
160 return STATUS_INVALID_PARAMETER
;
163 /* Return the data */
164 Option
= MiscGetBootOption(List
, Type
);
167 /* Extract the string */
168 String
= (PWCHAR
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
172 /* No string is present */
176 /* Compute the data size */
177 StringLength
= Option
->DataSize
/ sizeof(WCHAR
);
180 /* Filter out SecureBoot Options */
181 AppIdentifier
= BlGetApplicationIdentifier();
182 Status
= BlpBootOptionCallbackString(AppIdentifier
, Type
, String
, StringLength
, &String
, &StringLength
);
184 Status
= STATUS_SUCCESS
;
187 /* Check if we have space for one more character */
188 CopyLength
= StringLength
+ 1;
189 if (CopyLength
< StringLength
)
191 /* Nope, we'll overflow */
193 Status
= STATUS_INTEGER_OVERFLOW
;
198 Status
= STATUS_SUCCESS
;
202 if (NT_SUCCESS(Status
))
204 /* Check if it's safe to multiply by two */
205 if ((CopyLength
* sizeof(WCHAR
)) > 0xFFFFFFFF)
209 Status
= STATUS_INTEGER_OVERFLOW
;
213 /* We're good, do the multiplication */
214 Status
= STATUS_SUCCESS
;
215 CopyLength
*= sizeof(WCHAR
);
218 /* Allocate a copy for the string */
219 if (NT_SUCCESS(Status
))
221 StringCopy
= BlMmAllocateHeap(CopyLength
);
224 /* NULL-terminate it */
225 RtlCopyMemory(StringCopy
,
227 CopyLength
- sizeof(UNICODE_NULL
));
228 StringCopy
[CopyLength
] = UNICODE_NULL
;
230 Status
= STATUS_SUCCESS
;
234 /* No memory, fail */
235 Status
= STATUS_NO_MEMORY
;
245 BlGetBootOptionDevice (
246 _In_ PBL_BCD_OPTION List
,
248 _Out_ PBL_DEVICE_DESCRIPTOR
* Value
,
249 _In_opt_ PBL_BCD_OPTION
* ExtraOptions
253 PBL_BCD_OPTION Option
, ListData
, ListCopy
, SecureListData
;
254 PBCD_DEVICE_OPTION BcdDevice
;
255 ULONG DeviceSize
, ListOffset
, ListSize
;
256 PBL_DEVICE_DESCRIPTOR DeviceDescriptor
, SecureDescriptor
;
257 //PGUID AppIdentifier;
259 /* Make sure this is a BCD_DEVICE */
260 if ((Type
& 0xF000000) != 0x1000000)
262 return STATUS_INVALID_PARAMETER
;
265 /* Return the data */
266 Option
= MiscGetBootOption(List
, Type
);
269 /* Set failure if no data exists */
270 Status
= STATUS_NOT_FOUND
;
274 /* Otherwise, read the size of the BCD device encoded */
275 BcdDevice
= (PBCD_DEVICE_OPTION
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
276 DeviceSize
= BcdDevice
->DeviceDescriptor
.Size
;
278 /* Allocate a buffer to copy it into */
279 DeviceDescriptor
= BlMmAllocateHeap(DeviceSize
);
280 if (!DeviceDescriptor
)
282 return STATUS_NO_MEMORY
;
285 /* Copy it into that buffer */
286 RtlCopyMemory(DeviceDescriptor
, &BcdDevice
->DeviceDescriptor
, DeviceSize
);
287 Status
= STATUS_SUCCESS
;
290 /* Check if extra options were requested */
293 /* See where they are */
294 ListOffset
= Option
->ListOffset
;
297 /* See how big they are */
298 ListData
= (PBL_BCD_OPTION
)((ULONG_PTR
)Option
+ ListOffset
);
299 ListSize
= BlGetBootOptionListSize(ListData
);
301 /* Allocate a buffer to hold them into */
302 ListCopy
= BlMmAllocateHeap(ListSize
);
305 Status
= STATUS_NO_MEMORY
;
309 /* Copy them in there */
310 RtlCopyMemory(ListCopy
, ListData
, ListSize
);
315 /* Filter out SecureBoot Options */
316 AppIdentifier
= BlGetApplicationIdentifier();
317 if (BlpBootOptionCallbacks
)
319 DeviceCallback
= BlpBootOptionCallbacks
->Device
;
322 Status
= DeviceCallback(BlpBootOptionCallbackCookie
,
332 /* No secure boot, so the secure descriptors are the standard ones */
333 Status
= STATUS_SUCCESS
;
334 SecureDescriptor
= DeviceDescriptor
;
335 SecureListData
= ListCopy
;
338 /* Check if the data was read correctly */
339 if (NT_SUCCESS(Status
))
341 /* Check if we had a new descriptor after filtering */
342 if (SecureDescriptor
!= DeviceDescriptor
)
344 /* Yep -- if we had an old one, free it */
345 if (DeviceDescriptor
)
347 BlMmFreeHeap(DeviceDescriptor
);
351 /* Check if we had a new list after filtering */
352 if (SecureListData
!= ListCopy
)
354 /* Yep -- if we had an old list, free it */
357 BlMmFreeHeap(ListCopy
);
361 /* Finally, check if the caller wanted extra options */
364 /* Yep -- so pass the caller our copy */
365 *ExtraOptions
= ListCopy
;
369 /* Caller always wants data back, so pass them our copy */
370 *Value
= DeviceDescriptor
;
371 DeviceDescriptor
= NULL
;
375 /* On the failure path, if these buffers are active, we should free them */
378 BlMmFreeHeap(ListCopy
);
380 if (DeviceDescriptor
)
382 BlMmFreeHeap(DeviceDescriptor
);
390 BlGetBootOptionInteger (
391 _In_ PBL_BCD_OPTION List
,
393 _Out_ PULONGLONG Value
397 PBL_BCD_OPTION Option
;
398 //PGUID AppIdentifier;
400 /* Make sure this is a BCD_INTEGER */
401 if ((Type
& 0xF000000) != 0x5000000)
403 return STATUS_INVALID_PARAMETER
;
406 /* Return the data */
407 Option
= MiscGetBootOption(List
, Type
);
410 *Value
= *(PULONGLONG
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
414 /* Filter out SecureBoot Options */
415 AppIdentifier
= BlGetApplicationIdentifier();
416 Status
= BlpBootOptionCallbackULongLong(AppIdentifier
, Type
, Value
);
419 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
425 BlGetBootOptionBoolean (
426 _In_ PBL_BCD_OPTION List
,
432 PBL_BCD_OPTION Option
;
433 //PGUID AppIdentifier;
435 /* Make sure this is a BCD_BOOLEAN */
436 if ((Type
& 0xF000000) != 0x6000000)
438 return STATUS_INVALID_PARAMETER
;
441 /* Return the data */
442 Option
= MiscGetBootOption(List
, Type
);
445 *Value
= *(PBOOLEAN
)((ULONG_PTR
)Option
+ Option
->DataOffset
);
449 /* Filter out SecureBoot Options */
450 AppIdentifier
= BlGetApplicationIdentifier();
451 Status
= BlpBootOptionCallbackBoolean(AppIdentifier
, Type
, Value
);
454 Status
= Option
? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
459 #define BI_FLUSH_HIVE 0x01
461 typedef struct _BI_KEY_HIVE
464 PBL_FILE_PATH_DESCRIPTOR FilePath
;
468 } BI_KEY_HIVE
, *PBI_KEY_HIVE
;
470 typedef struct _BI_KEY_OBJECT
472 PBI_KEY_HIVE KeyHive
;
473 PCM_KEY_NODE KeyNode
;
476 } BI_KEY_OBJECT
, *PBI_KEY_OBJECT
;
486 UNREFERENCED_PARAMETER(Paged
);
487 UNREFERENCED_PARAMETER(Tag
);
489 /* Call the heap allocator */
490 return BlMmAllocateHeap(Size
);
500 UNREFERENCED_PARAMETER(Quota
);
502 /* Call the heap allocator */
509 _In_ HANDLE KeyHandle
512 PBI_KEY_OBJECT KeyObject
;
514 /* Get the key object */
515 KeyObject
= (PBI_KEY_OBJECT
)KeyHandle
;
517 /* Drop a reference on the parent hive */
518 --KeyObject
->KeyHive
->ReferenceCount
;
523 _In_ HANDLE KeyHandle
526 /* Not yet implemented */
527 EfiPrintf(L
"NO reg flush\r\n");
533 _In_ HANDLE KeyHandle
536 PBI_KEY_HIVE KeyHive
;
537 PBI_KEY_OBJECT KeyObject
;
539 /* Get the key object and hive */
540 KeyObject
= (PBI_KEY_OBJECT
)KeyHandle
;
541 KeyHive
= KeyObject
->KeyHive
;
543 /* Check if we have a hive, or name, or key node */
544 if ((KeyHive
) || (KeyObject
->KeyNode
) || (KeyObject
->KeyName
))
546 /* Drop a reference, see if it's the last one */
547 BiDereferenceHive(KeyHandle
);
548 if (!KeyHive
->ReferenceCount
)
550 /* Check if we should flush it */
551 if (KeyHive
->Flags
& BI_FLUSH_HIVE
)
553 BiFlushHive(KeyHandle
);
557 //MmPapFreePages(KeyHive->ImageBase, 1);
558 EfiPrintf(L
"Leaking hive memory\r\n");
560 /* Free the hive and hive path */
561 BlMmFreeHeap(KeyHive
->FilePath
);
562 BlMmFreeHeap(KeyHive
);
565 /* Check if a key name is present */
566 if (KeyObject
->KeyName
)
569 BlMmFreeHeap(KeyObject
->KeyName
);
573 /* Free the object */
574 BlMmFreeHeap(KeyObject
);
579 _In_ HANDLE ParentHandle
,
584 PBI_KEY_OBJECT ParentKey
, NewKey
;
585 PBI_KEY_HIVE ParentHive
;
587 ULONG NameLength
, SubNameLength
, NameBytes
;
588 PWCHAR NameStart
, NameBuffer
;
589 UNICODE_STRING KeyString
;
592 PCM_KEY_NODE ParentNode
;
594 /* Convert from a handle to our key object */
595 ParentKey
= (PBI_KEY_OBJECT
)ParentHandle
;
597 /* Extract the hive and node information */
598 ParentHive
= ParentKey
->KeyHive
;
599 ParentNode
= ParentKey
->KeyNode
;
600 Hive
= &ParentKey
->KeyHive
->Hive
.Hive
;
602 /* Initialize variables */
604 Status
= STATUS_SUCCESS
;
607 /* Loop as long as there's still portions of the key name in play */
608 NameLength
= wcslen(KeyName
);
611 /* Find the first path separator */
612 NameStart
= wcschr(KeyName
, OBJ_NAME_PATH_SEPARATOR
);
615 /* Look only at the key before the separator */
616 SubNameLength
= NameStart
- KeyName
;
621 /* No path separator, this is the final leaf key */
622 SubNameLength
= NameLength
;
625 /* Free the name buffer from the previous pass if needed */
628 BlMmFreeHeap(NameBuffer
);
631 /* Allocate a buffer to hold the name of this specific subkey only */
632 NameBytes
= SubNameLength
* sizeof(WCHAR
);
633 NameBuffer
= BlMmAllocateHeap(NameBytes
+ sizeof(UNICODE_NULL
));
636 Status
= STATUS_NO_MEMORY
;
640 /* Copy and null-terminate the name of the subkey */
641 RtlCopyMemory(NameBuffer
, KeyName
, NameBytes
);
642 NameBuffer
[SubNameLength
] = UNICODE_NULL
;
644 /* Convert it into a UNICODE_STRING and try to find it */
645 RtlInitUnicodeString(&KeyString
, NameBuffer
);
646 KeyCell
= CmpFindSubKeyByName(Hive
, ParentNode
, &KeyString
);
647 if (KeyCell
== HCELL_NIL
)
649 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
653 /* We found it -- get the key node out of it */
654 ParentNode
= (PCM_KEY_NODE
)Hive
->GetCellRoutine(Hive
, KeyCell
);
657 Status
= STATUS_REGISTRY_CORRUPT
;
661 /* Update the key name to the next remaining path element */
665 /* Update the length to the remainder of the path */
666 NameLength
+= -1 - SubNameLength
;
670 /* There's nothing left, this was the leaf key */
675 /* Allocate a key object */
676 NewKey
= BlMmAllocateHeap(sizeof(*NewKey
));
679 /* Bail out if we had no memory for it */
680 Status
= STATUS_NO_MEMORY
;
684 /* Fill out the key object data */
685 NewKey
->KeyNode
= ParentNode
;
686 NewKey
->KeyHive
= ParentHive
;
687 NewKey
->KeyName
= NameBuffer
;
688 NewKey
->KeyCell
= KeyCell
;
690 /* Add a reference to the hive */
691 ++ParentHive
->ReferenceCount
;
693 /* Return the object back to the caller */
697 /* If we had a name buffer, free it */
700 BlMmFreeHeap(NameBuffer
);
703 /* Return status of the open operation */
709 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
710 _Out_ PHANDLE HiveHandle
714 EfiPrintf(L
"Loading a hive is not yet implemented\r\n");
716 return STATUS_NOT_IMPLEMENTED
;
721 _In_ PBL_FILE_PATH_DESCRIPTOR FilePath
,
722 _Out_ PHANDLE StoreHandle
726 HANDLE HiveHandle
, KeyHandle
;
728 /* Load the specified hive */
729 Status
= BiLoadHive(FilePath
, &HiveHandle
);
730 if (!NT_SUCCESS(Status
))
735 /* Open the description key to make sure this is really a BCD */
736 Status
= BiOpenKey(HiveHandle
, L
"Description", &KeyHandle
);
737 if (NT_SUCCESS(Status
))
739 /* It is -- close the key as we don't need it */
740 BiCloseKey(KeyHandle
);
741 *StoreHandle
= HiveHandle
;
745 /* Failure, drop a reference on the hive and close the key */
746 BiDereferenceHive(HiveHandle
);
747 BiCloseKey(HiveHandle
);
750 /* Return the status */
755 BcdOpenStoreFromFile (
756 _In_ PUNICODE_STRING FileName
,
757 _In_ PHANDLE StoreHandle
761 PBL_FILE_PATH_DESCRIPTOR FilePath
;
768 /* Allocate a path descriptor */
769 Length
= FileName
->Length
+ sizeof(*FilePath
);
770 FilePath
= BlMmAllocateHeap(Length
);
773 return STATUS_NO_MEMORY
;
777 FilePath
->Version
= 1;
778 FilePath
->PathType
= InternalPath
;
779 FilePath
->Length
= Length
;
781 /* Copy the name and NULL-terminate it */
782 RtlCopyMemory(FilePath
->Path
, FileName
->Buffer
, Length
);
783 FilePath
->Path
[Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
786 Status
= BiAddStoreFromFile(FilePath
, &LocalHandle
);
787 if (NT_SUCCESS(Status
))
789 /* Return the handle on success */
790 *StoreHandle
= LocalHandle
;
793 /* Free the descriptor and return the status */
794 BlMmFreeHeap(FilePath
);