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
MiscGetBootOption(_In_ PBL_BCD_OPTION List,_In_ ULONG Type)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
BlGetBootOptionListSize(_In_ PBL_BCD_OPTION BcdOption)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
BlGetBootOptionSize(_In_ PBL_BCD_OPTION BcdOption)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
BlGetBootOptionString(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PWCHAR * Value)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
BlGetBootOptionGuid(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PGUID Value)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
BlGetBootOptionGuidList(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PGUID * Value,_In_ PULONG Count)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
BlGetBootOptionDevice(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PBL_DEVICE_DESCRIPTOR * Value,_In_opt_ PBL_BCD_OPTION * ExtraOptions)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
BlGetBootOptionInteger(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PULONGLONG Value)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
BlGetBootOptionBoolean(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PBOOLEAN Value)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
BlpGetBootOptionIntegerList(_In_ PBL_BCD_OPTION List,_In_ ULONG Type,_Out_ PULONGLONG * Value,_Out_ PULONGLONG Count,_In_ BOOLEAN NoCopy)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
BlCopyBootOptions(_In_ PBL_BCD_OPTION OptionList,_Out_ PBL_BCD_OPTION * CopiedOptions)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
BlAppendBootOptionBoolean(_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,_In_ ULONG OptionId,_In_ BOOLEAN Value)625 BlAppendBootOptionBoolean (
626 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
627 _In_ ULONG OptionId,
628 _In_ BOOLEAN Value
629 )
630 {
631 NTSTATUS Status;
632 PBL_BCD_OPTION Option;
633
634 /* Allocate space for the entry -- remember BOOLEANs are USHORTs in BCD */
635 Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(USHORT));
636 if (!Option)
637 {
638 return STATUS_NO_MEMORY;
639 }
640
641 /* Initialize it and set the boolean to TRUE */
642 RtlZeroMemory(Option, sizeof(*Option) + sizeof(USHORT));
643 Option->DataSize = sizeof(USHORT);
644 Option->Type = OptionId;
645 Option->DataOffset = sizeof(*Option);
646 *(PBOOLEAN)(Option + 1) = Value;
647
648 /* Append it */
649 Status = BlAppendBootOptions(AppEntry, Option);
650
651 /* We're all done, free our initial option */
652 BlMmFreeHeap(Option);
653 return Status;
654 }
655
656 NTSTATUS
BlAppendBootOptionInteger(_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,_In_ ULONG OptionId,_In_ ULONGLONG Value)657 BlAppendBootOptionInteger (
658 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
659 _In_ ULONG OptionId,
660 _In_ ULONGLONG Value
661 )
662 {
663 NTSTATUS Status;
664 PBL_BCD_OPTION Option;
665
666 /* Allocate space for the entry */
667 Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(Value));
668 if (!Option)
669 {
670 return STATUS_NO_MEMORY;
671 }
672
673 /* Initialize it and set the integer to the given value */
674 RtlZeroMemory(Option, sizeof(*Option) + sizeof(Value));
675 Option->DataSize = sizeof(Value);
676 Option->Type = OptionId;
677 Option->DataOffset = sizeof(*Option);
678 *(PULONGLONG)(Option + 1) = Value;
679
680 /* Append it */
681 Status = BlAppendBootOptions(AppEntry, Option);
682
683 /* We're all done, free our initial option */
684 BlMmFreeHeap(Option);
685 return Status;
686 }
687
688 NTSTATUS
BlAppendBootOptionString(_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,_In_ ULONG OptionId,_In_ PWCHAR OptionString)689 BlAppendBootOptionString (
690 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
691 _In_ ULONG OptionId,
692 _In_ PWCHAR OptionString
693 )
694 {
695 NTSTATUS Status;
696 ULONG StringSize;
697 PBL_BCD_OPTION Option;
698
699 /* Get the length in bytes */
700 Status = RtlULongLongToULong(wcslen(OptionString) * sizeof(WCHAR),
701 &StringSize);
702 if (!NT_SUCCESS(Status))
703 {
704 return Status;
705 }
706
707 /* Add a NULL-terminator */
708 Status = RtlULongAdd(StringSize, sizeof(UNICODE_NULL), &StringSize);
709 if (!NT_SUCCESS(Status))
710 {
711 return Status;
712 }
713
714 /* Allocate space for the entry */
715 Option = BlMmAllocateHeap(sizeof(*Option) + StringSize);
716 if (!Option)
717 {
718 return STATUS_NO_MEMORY;
719 }
720
721 /* Initialize it and copy the string value */
722 RtlZeroMemory(Option, sizeof(*Option) + StringSize);
723 Option->DataSize = StringSize;
724 Option->Type = OptionId;
725 Option->DataOffset = sizeof(*Option);
726 wcsncpy((PWCHAR)Option + 1, OptionString, StringSize / sizeof(WCHAR));
727
728 /* Append it */
729 Status = BlAppendBootOptions(AppEntry, Option);
730
731 /* We're all done, free our initial option */
732 BlMmFreeHeap(Option);
733 return Status;
734 }
735
736 NTSTATUS
BlAppendBootOptions(_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,_In_ PBL_BCD_OPTION Options)737 BlAppendBootOptions (
738 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
739 _In_ PBL_BCD_OPTION Options
740 )
741 {
742 ULONG OptionsSize, CurrentSize;
743 PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption;
744 NTSTATUS Status;
745 ULONG CurrentOffset;
746
747 /* Get the current options */
748 CurrentOptions = AppEntry->BcdData;
749
750 /* Calculate the size of the current, and the appended options */
751 CurrentSize = BlGetBootOptionListSize(CurrentOptions);
752 OptionsSize = BlGetBootOptionListSize(Options);
753
754 /* Allocate a buffer for the concatenated (new) options */
755 NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize);
756 if (!NewOptions)
757 {
758 return STATUS_NO_MEMORY;
759 }
760
761 /* Copy the old options, and the ones to be added */
762 RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize);
763 RtlCopyMemory((PVOID)((ULONG_PTR)NewOptions + CurrentSize),
764 Options,
765 OptionsSize);
766
767 /* We made it! */
768 Status = STATUS_SUCCESS;
769
770 /* Scan through to the last option in the list */
771 CurrentOffset = 0;
772 do
773 {
774 NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset);
775 CurrentOffset = NextOption->NextEntryOffset;
776 } while (CurrentOffset);
777
778 /* Every other option now has to have its offset adjusted */
779 do
780 {
781 NextOption->NextEntryOffset += CurrentSize;
782 NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset);
783 } while (NextOption->NextEntryOffset);
784
785 /* If we already had internal options, free them */
786 if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
787 {
788 BlMmFreeHeap(AppEntry->BcdData);
789 }
790
791 /* Write the new pointer */
792 AppEntry->BcdData = NewOptions;
793
794 /* Options are now internal, not external */
795 AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
796 AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
797 return Status;
798 }
799
800 VOID
BlRemoveBootOption(_In_ PBL_BCD_OPTION List,_In_ ULONG Type)801 BlRemoveBootOption (
802 _In_ PBL_BCD_OPTION List,
803 _In_ ULONG Type
804 )
805 {
806 PBL_BCD_OPTION Option;
807
808 /* Keep going until the option is gone */
809 while (1)
810 {
811 /* Get the BCD option */
812 Option = MiscGetBootOption(List, Type);
813 if (!Option)
814 {
815 break;
816 }
817
818 /* Pretend it's empty */
819 Option->Empty = TRUE;
820 }
821 }
822
823 NTSTATUS
BlReplaceBootOptions(_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,_In_ PBL_BCD_OPTION OldOptions)824 BlReplaceBootOptions (
825 _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
826 _In_ PBL_BCD_OPTION OldOptions
827 )
828 {
829 NTSTATUS Status;
830 ULONG OptionSize;
831 PBL_BCD_OPTION NewOptions;
832
833 /* Make sure there's something to replace with */
834 if (!OldOptions)
835 {
836 return STATUS_INVALID_PARAMETER;
837 }
838
839 /* Check if we already had allocated internal options */
840 if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
841 {
842 /* Free them */
843 BlMmFreeHeap(AppEntry->BcdData);
844 }
845
846 /* Reset option flags */
847 AppEntry->Flags &= ~(BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL |
848 BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL);
849
850 /* Reset the options and set success for now */
851 Status = STATUS_SUCCESS;
852 AppEntry->BcdData = NULL;
853
854 /* Get the size of the new list of options */
855 OptionSize = BlGetBootOptionListSize(OldOptions);
856
857 /* Allocate a copy of the new list */
858 NewOptions = BlMmAllocateHeap(OptionSize);
859 if (!NewOptions)
860 {
861 return STATUS_NO_MEMORY;
862 }
863
864 /* Copy it in */
865 RtlCopyMemory(NewOptions, OldOptions, OptionSize);
866
867 /* Set it as the new set of options and return */
868 AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
869 AppEntry->BcdData = NewOptions;
870 return Status;
871 }
872
873