0b4f82e46775395ecf6f5ad38674db02fe449283
[reactos.git] / boot / environ / lib / misc / bcdopt.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12 #include <bcd.h>
13
14 /* FUNCTIONS *****************************************************************/
15
16 PBL_BCD_OPTION
17 MiscGetBootOption (
18 _In_ PBL_BCD_OPTION List,
19 _In_ ULONG Type
20 )
21 {
22 ULONG_PTR NextOption = 0, ListOption;
23 PBL_BCD_OPTION Option, FoundOption;
24
25 /* No options, bail out */
26 if (!List)
27 {
28 return NULL;
29 }
30
31 /* Loop while we find an option */
32 FoundOption = NULL;
33 do
34 {
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))
38 {
39 FoundOption = Option;
40 break;
41 }
42
43 /* Store the offset of the next option */
44 NextOption = Option->NextEntryOffset;
45
46 /* Failed to match. Check for list options */
47 ListOption = Option->ListOffset;
48 if (ListOption)
49 {
50 /* Try to get a match in the associated option */
51 Option = MiscGetBootOption((PBL_BCD_OPTION)((ULONG_PTR)Option +
52 ListOption),
53 Type);
54 if (Option)
55 {
56 /* Return it */
57 FoundOption = Option;
58 break;
59 }
60 }
61 } while (NextOption);
62
63 /* Return the option that was found, if any */
64 return FoundOption;
65 }
66
67 /*++
68 * @name BlGetBootOptionListSize
69 *
70 * The BlGetBootOptionListSize routine
71 *
72 * @param BcdOption
73 * UEFI Image Handle for the current loaded application.
74 *
75 * @return Size of the BCD option
76 *
77 *--*/
78 ULONG
79 BlGetBootOptionListSize (
80 _In_ PBL_BCD_OPTION BcdOption
81 )
82 {
83 ULONG Size = 0, NextOffset = 0;
84 PBL_BCD_OPTION NextOption;
85
86 /* Loop all the options*/
87 do
88 {
89 /* Move to the next one */
90 NextOption = (PBL_BCD_OPTION)((ULONG_PTR)BcdOption + NextOffset);
91
92 /* Compute the size of the next one */
93 Size += BlGetBootOptionSize(NextOption);
94
95 /* Update the offset */
96 NextOffset = NextOption->NextEntryOffset;
97 } while (NextOffset);
98
99 /* Return final computed size */
100 return Size;
101 }
102
103 /*++
104 * @name BlGetBootOptionSize
105 *
106 * The BlGetBootOptionSize routine
107 *
108 * @param BcdOption
109 * UEFI Image Handle for the current loaded application.
110 *
111 * @return Size of the BCD option
112 *
113 *--*/
114 ULONG
115 BlGetBootOptionSize (
116 _In_ PBL_BCD_OPTION BcdOption
117 )
118 {
119 ULONG Size, Offset;
120
121 /* Check if there's any data */
122 if (BcdOption->DataOffset)
123 {
124 /* Add the size of the data */
125 Size = BcdOption->DataOffset + BcdOption->DataSize;
126 }
127 else
128 {
129 /* No data, just the structure itself */
130 Size = sizeof(*BcdOption);
131 }
132
133 /* Any associated options? */
134 Offset = BcdOption->ListOffset;
135 if (Offset)
136 {
137 /* Go get those too */
138 Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
139 }
140
141 /* Return the final size */
142 return Size;
143 }
144
145 NTSTATUS
146 BlGetBootOptionString (
147 _In_ PBL_BCD_OPTION List,
148 _In_ ULONG Type,
149 _Out_ PWCHAR* Value
150 )
151 {
152 NTSTATUS Status;
153 PBL_BCD_OPTION Option;
154 PWCHAR String, StringCopy;
155 ULONG StringLength;
156 BcdElementType ElementType;
157 //PGUID AppIdentifier;
158
159 /* Make sure this is a BCD_STRING */
160 ElementType.PackedValue = Type;
161 if (ElementType.Format != BCD_TYPE_STRING)
162 {
163 return STATUS_INVALID_PARAMETER;
164 }
165
166 /* Return the data */
167 Option = MiscGetBootOption(List, Type);
168 if (Option)
169 {
170 /* Extract the string */
171 String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset);
172 Status = STATUS_SUCCESS;
173 }
174 else
175 {
176 /* No string is present */
177 String = NULL;
178 Status = STATUS_NOT_FOUND;
179 }
180
181 /* Compute the data size */
182 StringLength = Option->DataSize / sizeof(WCHAR);
183
184 #ifdef _SECURE_BOOT_
185 /* Filter out SecureBoot Options */
186 AppIdentifier = BlGetApplicationIdentifier();
187 Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength);
188 #else
189 #endif
190
191 /* Make sure we have a valid, non-filtered string */
192 if (NT_SUCCESS(Status))
193 {
194 /* Check if we have space for one more character */
195 Status = RtlULongAdd(StringLength, 1, &StringLength);
196 if (NT_SUCCESS(Status))
197 {
198 /* Check if it's safe to multiply by two */
199 Status = RtlULongMult(StringLength, sizeof(WCHAR), &StringLength);
200 if (NT_SUCCESS(Status))
201 {
202 /* Allocate a copy for the string */
203 StringCopy = BlMmAllocateHeap(StringLength);
204 if (StringCopy)
205 {
206 /* NULL-terminate it */
207 RtlCopyMemory(StringCopy,
208 String,
209 StringLength - sizeof(UNICODE_NULL));
210 StringCopy[StringLength] = UNICODE_NULL;
211 *Value = StringCopy;
212 Status = STATUS_SUCCESS;
213 }
214 else
215 {
216 /* No memory, fail */
217 Status = STATUS_NO_MEMORY;
218 }
219 }
220 }
221 }
222
223 /* All done */
224 return Status;
225 }
226
227 NTSTATUS
228 BlGetBootOptionGuid (
229 _In_ PBL_BCD_OPTION List,
230 _In_ ULONG Type,
231 _Out_ PGUID Value
232 )
233 {
234 NTSTATUS Status;
235 PBL_BCD_OPTION Option;
236 PGUID Guid;
237 BcdElementType ElementType;
238
239 /* Make sure this is a BCD_TYPE_OBJECT */
240 ElementType.PackedValue = Type;
241 if (ElementType.Format != BCD_TYPE_OBJECT)
242 {
243 return STATUS_INVALID_PARAMETER;
244 }
245
246 /* Return the data */
247 Option = MiscGetBootOption(List, Type);
248 if (!Option)
249 {
250 /* Set failure if no data exists */
251 Status = STATUS_NOT_FOUND;
252 }
253 else
254 {
255 /* Copy the GUID */
256 Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
257 RtlCopyMemory(Value, Guid, Option->DataSize);
258 Status = STATUS_SUCCESS;
259 }
260
261 /* All good */
262 return Status;
263 }
264
265 NTSTATUS
266 BlGetBootOptionGuidList (
267 _In_ PBL_BCD_OPTION List,
268 _In_ ULONG Type,
269 _Out_ PGUID *Value,
270 _In_ PULONG Count
271 )
272 {
273 NTSTATUS Status;
274 PBL_BCD_OPTION Option;
275 PGUID GuidCopy, Guid;
276 ULONG GuidCount;
277 BcdElementType ElementType;
278
279 /* Make sure this is a BCD_TYPE_OBJECT_LIST */
280 ElementType.PackedValue = Type;
281 if (ElementType.Format != BCD_TYPE_OBJECT_LIST)
282 {
283 return STATUS_INVALID_PARAMETER;
284 }
285
286 /* Return the data */
287 Option = MiscGetBootOption(List, Type);
288 if (!Option)
289 {
290 /* Set failure if no data exists */
291 Status = STATUS_NOT_FOUND;
292 }
293 else
294 {
295 /* Get the GUIDs and allocate a copy for them */
296 Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
297 GuidCopy = BlMmAllocateHeap(Option->DataSize);
298 if (GuidCopy)
299 {
300 /* Copy the GUIDs */
301 RtlCopyMemory(GuidCopy, Guid, Option->DataSize);
302
303 /* Return the number of GUIDs and the start of the array */
304 GuidCount = Option->DataSize / sizeof(GUID);
305 *Value = GuidCopy;
306 *Count = GuidCount;
307 Status = STATUS_SUCCESS;
308 }
309 else
310 {
311 /* No memory for the copy */
312 Status = STATUS_NO_MEMORY;
313 }
314 }
315
316 /* All good */
317 return Status;
318 }
319
320 NTSTATUS
321 BlGetBootOptionDevice (
322 _In_ PBL_BCD_OPTION List,
323 _In_ ULONG Type,
324 _Out_ PBL_DEVICE_DESCRIPTOR* Value,
325 _In_opt_ PBL_BCD_OPTION* ExtraOptions
326 )
327 {
328 NTSTATUS Status;
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;
335
336 /* Make sure this is a BCD_TYPE_DEVICE */
337 ElementType.PackedValue = Type;
338 if (ElementType.Format != BCD_TYPE_DEVICE)
339 {
340 return STATUS_INVALID_PARAMETER;
341 }
342
343 /* Return the data */
344 Option = MiscGetBootOption(List, Type);
345 if (!Option)
346 {
347 /* Set failure if no data exists */
348 Status = STATUS_NOT_FOUND;
349 }
350 else
351 {
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;
355
356 /* Allocate a buffer to copy it into */
357 DeviceDescriptor = BlMmAllocateHeap(DeviceSize);
358 if (!DeviceDescriptor)
359 {
360 return STATUS_NO_MEMORY;
361 }
362
363 /* Copy it into that buffer */
364 RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize);
365 Status = STATUS_SUCCESS;
366 }
367
368 /* Check if extra options were requested */
369 if (ExtraOptions)
370 {
371 /* See where they are */
372 ListOffset = Option->ListOffset;
373 if (ListOffset)
374 {
375 /* See how big they are */
376 ListData = (PBL_BCD_OPTION)((ULONG_PTR)Option + ListOffset);
377 ListSize = BlGetBootOptionListSize(ListData);
378
379 /* Allocate a buffer to hold them into */
380 ListCopy = BlMmAllocateHeap(ListSize);
381 if (!ListCopy)
382 {
383 Status = STATUS_NO_MEMORY;
384 goto Quickie;
385 }
386
387 /* Copy them in there */
388 RtlCopyMemory(ListCopy, ListData, ListSize);
389 }
390 }
391
392 #ifdef _SECURE_BOOT_
393 /* Filter out SecureBoot Options */
394 AppIdentifier = BlGetApplicationIdentifier();
395 if (BlpBootOptionCallbacks)
396 {
397 DeviceCallback = BlpBootOptionCallbacks->Device;
398 if (DeviceCallback)
399 {
400 Status = DeviceCallback(BlpBootOptionCallbackCookie,
401 Status,
402 0,
403 AppIdentifier,
404 Type,
405 &SecureDescriptor,
406 PtrOptionData);
407 }
408 }
409 #else
410 /* No secure boot, so the secure descriptors are the standard ones */
411 SecureDescriptor = DeviceDescriptor;
412 SecureListData = ListCopy;
413 #endif
414
415 /* Check if the data was read correctly */
416 if (NT_SUCCESS(Status))
417 {
418 /* Check if we had a new descriptor after filtering */
419 if (SecureDescriptor != DeviceDescriptor)
420 {
421 /* Yep -- if we had an old one, free it */
422 if (DeviceDescriptor)
423 {
424 BlMmFreeHeap(DeviceDescriptor);
425 }
426 }
427
428 /* Check if we had a new list after filtering */
429 if (SecureListData != ListCopy)
430 {
431 /* Yep -- if we had an old list, free it */
432 if (ListCopy)
433 {
434 BlMmFreeHeap(ListCopy);
435 }
436 }
437
438 /* Finally, check if the caller wanted extra options */
439 if (ExtraOptions)
440 {
441 /* Yep -- so pass the caller our copy */
442 *ExtraOptions = ListCopy;
443 ListCopy = NULL;
444 }
445
446 /* Caller always wants data back, so pass them our copy */
447 *Value = DeviceDescriptor;
448 DeviceDescriptor = NULL;
449 }
450
451 Quickie:
452 /* On the failure path, if these buffers are active, we should free them */
453 if (ListCopy)
454 {
455 BlMmFreeHeap(ListCopy);
456 }
457 if (DeviceDescriptor)
458 {
459 BlMmFreeHeap(DeviceDescriptor);
460 }
461
462 /* All done */
463 return Status;
464 }
465
466 NTSTATUS
467 BlGetBootOptionInteger (
468 _In_ PBL_BCD_OPTION List,
469 _In_ ULONG Type,
470 _Out_ PULONGLONG Value
471 )
472 {
473 NTSTATUS Status;
474 PBL_BCD_OPTION Option;
475 //PGUID AppIdentifier;
476 BcdElementType ElementType;
477
478 /* Make sure this is a BCD_TYPE_INTEGER */
479 ElementType.PackedValue = Type;
480 if (ElementType.Format != BCD_TYPE_INTEGER)
481 {
482 return STATUS_INVALID_PARAMETER;
483 }
484
485 /* Return the data */
486 Option = MiscGetBootOption(List, Type);
487 if (Option)
488 {
489 *Value = *(PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
490 }
491
492 #ifdef _SECURE_BOOT_
493 /* Filter out SecureBoot Options */
494 AppIdentifier = BlGetApplicationIdentifier();
495 Status = BlpBootOptionCallbackULongLong(AppIdentifier, Type, Value);
496 #else
497 /* Option found */
498 Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
499 #endif
500 return Status;
501 }
502
503 NTSTATUS
504 BlGetBootOptionBoolean (
505 _In_ PBL_BCD_OPTION List,
506 _In_ ULONG Type,
507 _Out_ PBOOLEAN Value
508 )
509 {
510 NTSTATUS Status;
511 PBL_BCD_OPTION Option;
512 //PGUID AppIdentifier;
513 BcdElementType ElementType;
514
515 /* Make sure this is a BCD_TYPE_BOOLEAN */
516 ElementType.PackedValue = Type;
517 if (ElementType.Format != BCD_TYPE_BOOLEAN)
518 {
519 return STATUS_INVALID_PARAMETER;
520 }
521
522 /* Return the data */
523 Option = MiscGetBootOption(List, Type);
524 if (Option)
525 {
526 *Value = *(PBOOLEAN)((ULONG_PTR)Option + Option->DataOffset);
527 }
528
529 #ifdef _SECURE_BOOT_
530 /* Filter out SecureBoot Options */
531 AppIdentifier = BlGetApplicationIdentifier();
532 Status = BlpBootOptionCallbackBoolean(AppIdentifier, Type, Value);
533 #else
534 /* Option found */
535 Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
536 #endif
537 return Status;
538 }
539
540 NTSTATUS
541 BlpGetBootOptionIntegerList (
542 _In_ PBL_BCD_OPTION List,
543 _In_ ULONG Type,
544 _Out_ PULONGLONG* Value,
545 _Out_ PULONGLONG Count,
546 _In_ BOOLEAN NoCopy
547 )
548 {
549 PBL_BCD_OPTION Option;
550 BcdElementType ElementType;
551 PULONGLONG ValueCopy;
552
553 /* Make sure this is a BCD_TYPE_INTEGER_LIST */
554 ElementType.PackedValue = Type;
555 if (ElementType.Format != BCD_TYPE_INTEGER_LIST)
556 {
557 return STATUS_INVALID_PARAMETER;
558 }
559
560 /* Return the data */
561 Option = MiscGetBootOption(List, Type);
562 if (!Option)
563 {
564 return STATUS_NOT_FOUND;
565 }
566
567 /* Check if a copy should be made of it */
568 if (NoCopy)
569 {
570 /* Nope, return the raw value */
571 *Value = (PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
572 }
573 else
574 {
575 /* Allocate a buffer for the copy */
576 ValueCopy = BlMmAllocateHeap(Option->DataSize);
577 if (!ValueCopy)
578 {
579 return STATUS_NO_MEMORY;
580 }
581
582 /* Copy the data in */
583 RtlCopyMemory(ValueCopy,
584 (PVOID)((ULONG_PTR)Option + Option->DataOffset),
585 Option->DataSize);
586
587 /* Return our copy */
588 *Value = ValueCopy;
589 }
590
591 /* Return count and success */
592 *Count = Option->DataSize / sizeof(ULONGLONG);
593 return STATUS_SUCCESS;
594 }
595
596 NTSTATUS
597 BlCopyBootOptions (
598 _In_ PBL_BCD_OPTION OptionList,
599 _Out_ PBL_BCD_OPTION *CopiedOptions
600 )
601 {
602 NTSTATUS Status;
603 ULONG OptionSize;
604 PBL_BCD_OPTION Options;
605
606 /* Assume no options */
607 Status = STATUS_SUCCESS;
608 *CopiedOptions = NULL;
609
610 /* Get the size of the list and allocate a copy for it */
611 OptionSize = BlGetBootOptionListSize(OptionList);
612 Options = BlMmAllocateHeap(OptionSize);
613 if (!Options)
614 {
615 return STATUS_NO_MEMORY;
616 }
617
618 /* Make the copy and return it to the caller */
619 RtlCopyMemory(Options, OptionList, OptionSize);
620 *CopiedOptions = Options;
621 return Status;
622 }
623
624 NTSTATUS
625 BlAppendBootOptionBoolean (
626 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
627 _In_ ULONG OptionId
628 )
629 {
630 NTSTATUS Status;
631 PBL_BCD_OPTION Option;
632
633 /* Allocate space for the entry -- remember BOOLEANs are USHORTs in BCD */
634 Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(USHORT));
635 if (!Option)
636 {
637 return STATUS_NO_MEMORY;
638 }
639
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;
646
647 /* Append it */
648 Status = BlAppendBootOptions(AppEntry, Option);
649
650 /* We're all done, free our initial option */
651 BlMmFreeHeap(Option);
652 return Status;
653 }
654
655 NTSTATUS
656 BlAppendBootOptionInteger (
657 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
658 _In_ ULONG OptionId,
659 _In_ ULONGLONG Value
660 )
661 {
662 NTSTATUS Status;
663 PBL_BCD_OPTION Option;
664
665 /* Allocate space for the entry */
666 Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(Value));
667 if (!Option)
668 {
669 return STATUS_NO_MEMORY;
670 }
671
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;
678
679 /* Append it */
680 Status = BlAppendBootOptions(AppEntry, Option);
681
682 /* We're all done, free our initial option */
683 BlMmFreeHeap(Option);
684 return Status;
685 }
686
687 NTSTATUS
688 BlAppendBootOptionString (
689 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
690 _In_ PWCHAR OptionString
691 )
692 {
693 NTSTATUS Status;
694 ULONG StringSize;
695 PBL_BCD_OPTION Option;
696
697 /* Get the length in bytes */
698 Status = RtlULongLongToULong(wcslen(OptionString) * sizeof(WCHAR),
699 &StringSize);
700 if (!NT_SUCCESS(Status))
701 {
702 return Status;
703 }
704
705 /* Add a NULL-terminator */
706 Status = RtlULongAdd(StringSize, sizeof(UNICODE_NULL), &StringSize);
707 if (!NT_SUCCESS(Status))
708 {
709 return Status;
710 }
711
712 /* Allocate space for the entry */
713 Option = BlMmAllocateHeap(sizeof(*Option) + StringSize);
714 if (!Option)
715 {
716 return STATUS_NO_MEMORY;
717 }
718
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));
725
726 /* Append it */
727 Status = BlAppendBootOptions(AppEntry, Option);
728
729 /* We're all done, free our initial option */
730 BlMmFreeHeap(Option);
731 return Status;
732 }
733
734 NTSTATUS
735 BlAppendBootOptions (
736 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
737 _In_ PBL_BCD_OPTION Options
738 )
739 {
740 ULONG OptionsSize, CurrentSize;
741 PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption;
742 NTSTATUS Status;
743 ULONG CurrentOffset;
744
745 /* Get the current options */
746 CurrentOptions = AppEntry->BcdData;
747
748 /* Calculate the size of the current, and the appended options */
749 CurrentSize = BlGetBootOptionListSize(CurrentOptions);
750 OptionsSize = BlGetBootOptionListSize(Options);
751
752 /* Allocate a buffer for the concatenated (new) options */
753 NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize);
754 if (!NewOptions)
755 {
756 return STATUS_NO_MEMORY;
757 }
758
759 /* Copy the old options, and the ones to be added */
760 RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize);
761 RtlCopyMemory((PVOID)((ULONG_PTR)NewOptions + CurrentSize),
762 Options,
763 OptionsSize);
764
765 /* We made it! */
766 Status = STATUS_SUCCESS;
767
768 /* Scan through to the last option in the list */
769 CurrentOffset = 0;
770 do
771 {
772 NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset);
773 CurrentOffset = NextOption->NextEntryOffset;
774 } while (CurrentOffset);
775
776 /* Every other option now has to have its offset adjusted */
777 do
778 {
779 NextOption->NextEntryOffset += CurrentSize;
780 NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset);
781 } while (NextOption->NextEntryOffset);
782
783 /* If we already had internal options, free them */
784 if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
785 {
786 BlMmFreeHeap(AppEntry->BcdData);
787 }
788
789 /* Write the new pointer */
790 AppEntry->BcdData = NewOptions;
791
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;
795 return Status;
796 }
797
798 VOID
799 BlRemoveBootOption (
800 _In_ PBL_BCD_OPTION List,
801 _In_ ULONG Type
802 )
803 {
804 PBL_BCD_OPTION Option;
805
806 /* Keep going until the option is gone */
807 while (1)
808 {
809 /* Get the BCD option */
810 Option = MiscGetBootOption(List, Type);
811 if (!Option)
812 {
813 break;
814 }
815
816 /* Pretend it's empty */
817 Option->Empty = TRUE;
818 }
819 }
820
821 NTSTATUS
822 BlReplaceBootOptions (
823 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
824 _In_ PBL_BCD_OPTION OldOptions
825 )
826 {
827 NTSTATUS Status;
828 ULONG OptionSize;
829 PBL_BCD_OPTION NewOptions;
830
831 /* Make sure there's something to replace with */
832 if (!OldOptions)
833 {
834 return STATUS_INVALID_PARAMETER;
835 }
836
837 /* Check if we already had allocated internal options */
838 if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
839 {
840 /* Free them */
841 BlMmFreeHeap(AppEntry->BcdData);
842 }
843
844 /* Reset option flags */
845 AppEntry->Flags &= ~(BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL |
846 BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL);
847
848 /* Reset the options and set success for now */
849 Status = STATUS_SUCCESS;
850 AppEntry->BcdData = NULL;
851
852 /* Get the size of the new list of options */
853 OptionSize = BlGetBootOptionListSize(OldOptions);
854
855 /* Allocate a copy of the new list */
856 NewOptions = BlMmAllocateHeap(OptionSize);
857 if (!NewOptions)
858 {
859 return STATUS_NO_MEMORY;
860 }
861
862 /* Copy it in */
863 RtlCopyMemory(NewOptions, OldOptions, OptionSize);
864
865 /* Set it as the new set of options and return */
866 AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
867 AppEntry->BcdData = NewOptions;
868 return Status;
869 }
870