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 _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 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 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 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 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 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