1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Manager 4 * FILE: boot/environ/app/bootmgr/bootmgr.cla 5 * PURPOSE: Boot Manager Entrypoint 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bootmgr.h" 12 13 /* DATA VARIABLES ************************************************************/ 14 15 DEFINE_GUID(GUID_WINDOWS_BOOTMGR, 16 0x9DEA862C, 17 0x5CDD, 18 0x4E70, 19 0xAC, 0xC1, 0xF3, 0x2B, 0x34, 0x4D, 0x47, 0x95); 20 21 ULONGLONG ApplicationStartTime; 22 ULONGLONG PostTime; 23 GUID BmApplicationIdentifier; 24 PWCHAR BootDirectory; 25 26 BL_BOOT_ERROR BmpErrorBuffer; 27 PBL_BOOT_ERROR BmpInternalBootError; 28 BL_PACKED_BOOT_ERROR BmpPackedBootError; 29 30 BOOLEAN BmBootIniUsed; 31 WCHAR BmpFileNameBuffer[128]; 32 PWCHAR ParentFileName = L""; 33 34 BOOLEAN BmDisplayStateCached; 35 PBL_LOADED_APPLICATION_ENTRY* BmpFailedBootEntries; 36 PBL_LOADED_APPLICATION_ENTRY BmpSelectedBootEntry; 37 BOOLEAN BmBootEntryOverridePresent; 38 BOOLEAN BmpDisplayBootMenu; 39 40 /* FUNCTIONS *****************************************************************/ 41 42 NTSTATUS 43 BmGetOptionList ( 44 _In_ HANDLE BcdHandle, 45 _In_ PGUID ObjectId, 46 _In_ PBL_BCD_OPTION *OptionList 47 ) 48 { 49 NTSTATUS Status; 50 HANDLE ObjectHandle; 51 ULONG ElementSize, ElementCount, i, OptionsSize; 52 BcdElementType Type; 53 PBCD_ELEMENT_HEADER Header; 54 PBCD_ELEMENT BcdElements; 55 PBL_BCD_OPTION Options, Option, PreviousOption, DeviceOptions; 56 PBCD_DEVICE_OPTION DeviceOption; 57 GUID DeviceId; 58 PVOID DeviceData; 59 60 /* Open the BCD object requested */ 61 ObjectHandle = NULL; 62 BcdElements = NULL; 63 Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle); 64 if (!NT_SUCCESS(Status)) 65 { 66 goto Quickie; 67 } 68 69 /* Do the initial enumeration to get the size needed */ 70 ElementSize = 0; 71 Status = BcdEnumerateAndUnpackElements(BcdHandle, 72 ObjectHandle, 73 NULL, 74 &ElementSize, 75 &ElementCount); 76 if (Status != STATUS_BUFFER_TOO_SMALL) 77 { 78 /* If we got success, that doesn't make any sense */ 79 if (NT_SUCCESS(Status)) 80 { 81 Status = STATUS_INVALID_PARAMETER; 82 } 83 84 /* Bail out */ 85 goto Quickie; 86 } 87 88 /* Allocate a large-enough buffer */ 89 BcdElements = BlMmAllocateHeap(ElementSize); 90 if (!BcdElements) 91 { 92 Status = STATUS_NO_MEMORY; 93 goto Quickie; 94 } 95 96 /* Now do the real enumeration to fill out the elements buffer */ 97 Status = BcdEnumerateAndUnpackElements(BcdHandle, 98 ObjectHandle, 99 BcdElements, 100 &ElementSize, 101 &ElementCount); 102 if (!NT_SUCCESS(Status)) 103 { 104 goto Quickie; 105 } 106 107 /* Go through each BCD option to add the sizes up */ 108 OptionsSize = 0; 109 for (i = 0; i < ElementCount; i++) 110 { 111 OptionsSize += BcdElements[i].Header->Size + sizeof(BL_BCD_OPTION); 112 } 113 114 /* Allocate the required BCD option list */ 115 Options = BlMmAllocateHeap(OptionsSize); 116 if (!Options) 117 { 118 Status = STATUS_NO_MEMORY; 119 goto Quickie; 120 } 121 122 /* Zero it out */ 123 RtlZeroMemory(Options, OptionsSize); 124 125 /* Start going through each option */ 126 PreviousOption = NULL; 127 Option = Options; 128 for (i = 0; i < ElementCount; i++) 129 { 130 /* Read the header and type */ 131 Header = BcdElements[i].Header; 132 Type.PackedValue = Header->Type; 133 134 /* Check if this option isn't already present */ 135 if (!MiscGetBootOption(Options, Type.PackedValue)) 136 { 137 /* It's a new option. Did we have an existing one? */ 138 if (PreviousOption) 139 { 140 /* Link it to this new one */ 141 PreviousOption->NextEntryOffset = (ULONG_PTR)Option - 142 (ULONG_PTR)Options; 143 } 144 145 /* Capture the type, size, data, and offset */ 146 Option->Type = Type.PackedValue; 147 Option->DataSize = Header->Size; 148 RtlCopyMemory(Option + 1, BcdElements[i].Body, Header->Size); 149 Option->DataOffset = sizeof(BL_BCD_OPTION); 150 151 /* Check if this was a device */ 152 if (Type.Format == BCD_TYPE_DEVICE) 153 { 154 /* Grab its GUID */ 155 DeviceOption = (PBCD_DEVICE_OPTION)(Option + 1); 156 DeviceId = DeviceOption->AssociatedEntry; 157 158 /* Look up the options for that GUID */ 159 Status = BmGetOptionList(BcdHandle, &DeviceId, &DeviceOptions); 160 if (NT_SUCCESS(Status)) 161 { 162 /* Device data is after the device option */ 163 DeviceData = (PVOID)((ULONG_PTR)DeviceOption + Header->Size); 164 165 /* Copy it */ 166 RtlCopyMemory(DeviceData, 167 DeviceOptions, 168 BlGetBootOptionListSize(DeviceOptions)); 169 170 /* Don't need this anymore */ 171 BlMmFreeHeap(DeviceOptions); 172 173 /* Write the offset of the device options */ 174 Option->ListOffset = (ULONG_PTR)DeviceData - 175 (ULONG_PTR)Option; 176 } 177 } 178 179 /* Save the previous option and go to the next one */ 180 PreviousOption = Option; 181 Option = (PBL_BCD_OPTION)((ULONG_PTR)Option + 182 BlGetBootOptionSize(Option)); 183 } 184 } 185 186 /* Return the pointer back, we've made it! */ 187 *OptionList = Options; 188 Status = STATUS_SUCCESS; 189 190 Quickie: 191 /* Did we allocate a local buffer? Free it if so */ 192 if (BcdElements) 193 { 194 BlMmFreeHeap(BcdElements); 195 } 196 197 /* Was the key open? Close it if so */ 198 if (ObjectHandle) 199 { 200 BiCloseKey(ObjectHandle); 201 } 202 203 /* Return the option list parsing status */ 204 return Status; 205 } 206 207 NTSTATUS 208 BmpUpdateApplicationOptions ( 209 _In_ HANDLE BcdHandle 210 ) 211 { 212 NTSTATUS Status; 213 PBL_BCD_OPTION Options; 214 215 /* Get the boot option list */ 216 Status = BmGetOptionList(BcdHandle, &BmApplicationIdentifier, &Options); 217 if (!NT_SUCCESS(Status)) 218 { 219 return Status; 220 } 221 222 /* Append the options, free the local buffer, and return success */ 223 BlAppendBootOptions(&BlpApplicationEntry, Options); 224 BlMmFreeHeap(Options); 225 return STATUS_SUCCESS; 226 } 227 228 NTSTATUS 229 BmpFwGetApplicationDirectoryPath ( 230 _In_ PUNICODE_STRING ApplicationDirectoryPath 231 ) 232 { 233 NTSTATUS Status; 234 SIZE_T i, AppPathLength; 235 PWCHAR ApplicationPath, PathCopy; 236 237 /* Clear the incoming string */ 238 ApplicationDirectoryPath->Length = 0; 239 ApplicationDirectoryPath->MaximumLength = 0; 240 ApplicationDirectoryPath->Buffer = 0; 241 242 /* Get the boot application path */ 243 ApplicationPath = NULL; 244 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData, 245 BcdLibraryString_ApplicationPath, 246 &ApplicationPath); 247 if (NT_SUCCESS(Status)) 248 { 249 /* Calculate the length of the application path */ 250 for (i = wcslen(ApplicationPath) - 1; i > 0; i--) 251 { 252 /* Keep going until the path separator */ 253 if (ApplicationPath[i] == OBJ_NAME_PATH_SEPARATOR) 254 { 255 break; 256 } 257 } 258 259 /* Check if we have space for one more character */ 260 Status = RtlSIZETAdd(i, 1, &AppPathLength); 261 if (NT_SUCCESS(Status)) 262 { 263 /* Check if it's safe to multiply by two */ 264 Status = RtlSIZETMult(AppPathLength, sizeof(WCHAR), &AppPathLength); 265 if (NT_SUCCESS(Status)) 266 { 267 /* Allocate a copy for the string */ 268 PathCopy = BlMmAllocateHeap(AppPathLength); 269 if (PathCopy) 270 { 271 /* NULL-terminate it */ 272 RtlCopyMemory(PathCopy, 273 ApplicationPath, 274 AppPathLength - sizeof(UNICODE_NULL)); 275 PathCopy[AppPathLength] = UNICODE_NULL; 276 277 /* Finally, initialize the outgoing string */ 278 RtlInitUnicodeString(ApplicationDirectoryPath, PathCopy); 279 } 280 else 281 { 282 /* No memory, fail */ 283 Status = STATUS_NO_MEMORY; 284 } 285 } 286 } 287 } 288 289 /* Check if we had an application path */ 290 if (ApplicationPath) 291 { 292 /* No longer need this, free it */ 293 BlMmFreeHeap(ApplicationPath); 294 } 295 296 /* All done! */ 297 return Status; 298 } 299 300 NTSTATUS 301 BmFwInitializeBootDirectoryPath ( 302 VOID 303 ) 304 { 305 PWCHAR FinalPath; 306 NTSTATUS Status; 307 PWCHAR BcdDirectory; 308 UNICODE_STRING BcdPath; 309 ULONG FinalSize; 310 ULONG FileHandle, DeviceHandle; 311 312 /* Initialize everything for failure */ 313 BcdPath.MaximumLength = 0; 314 BcdPath.Buffer = NULL; 315 BcdDirectory = NULL; 316 FinalPath = NULL; 317 FileHandle = -1; 318 DeviceHandle = -1; 319 320 /* Try to open the boot device */ 321 Status = BlpDeviceOpen(BlpBootDevice, 322 BL_DEVICE_READ_ACCESS, 323 0, 324 &DeviceHandle); 325 if (!NT_SUCCESS(Status)) 326 { 327 EfiPrintf(L"Device open failed: %lx\r\n", Status); 328 goto Quickie; 329 } 330 331 /* Get the directory path */ 332 Status = BmpFwGetApplicationDirectoryPath(&BcdPath); 333 BcdDirectory = BcdPath.Buffer; 334 if (!NT_SUCCESS(Status)) 335 { 336 goto Quickie; 337 } 338 339 /* Add the BCD file name to it */ 340 FinalSize = BcdPath.MaximumLength + sizeof(L"\\BCD") - sizeof(UNICODE_NULL); 341 if (FinalSize < BcdPath.MaximumLength) 342 { 343 goto Quickie; 344 } 345 346 /* Allocate space for the final path */ 347 FinalPath = BlMmAllocateHeap(FinalSize); 348 if (!FinalPath) 349 { 350 goto Quickie; 351 } 352 353 /* Build it */ 354 RtlZeroMemory(FinalPath, FinalSize); 355 RtlCopyMemory(FinalPath, BcdDirectory, BcdPath.MaximumLength); 356 wcsncat(FinalPath, L"\\BCD", FinalSize / sizeof(WCHAR)); 357 358 /* Try to open the file */ 359 Status = BlFileOpen(DeviceHandle, 360 FinalPath, 361 BL_FILE_READ_ACCESS, 362 &FileHandle); 363 if (!NT_SUCCESS(Status)) 364 { 365 BootDirectory = BcdDirectory; 366 goto Quickie; 367 } 368 369 /* Save the boot directory */ 370 BootDirectory = L"\\EFI\\Boot"; /* Should be EFI\\ReactOS\\Boot */ 371 372 Quickie: 373 /* Free all the allocations we made */ 374 if (BcdDirectory) 375 { 376 Status = BlMmFreeHeap(BcdDirectory); 377 } 378 if (FinalPath) 379 { 380 Status = BlMmFreeHeap(FinalPath); 381 } 382 383 /* Close the BCD file */ 384 if (FileHandle != -1) 385 { 386 Status = BlFileClose(FileHandle); 387 } 388 389 /* Close the boot device */ 390 if (DeviceHandle != -1) 391 { 392 Status = BlDeviceClose(DeviceHandle); 393 } 394 395 /* Return back to the caller */ 396 return Status; 397 } 398 399 NTSTATUS 400 BmOpenBootIni ( 401 VOID 402 ) 403 { 404 /* Don't yet handled boot.ini */ 405 return STATUS_NOT_FOUND; 406 } 407 408 ULONG 409 BmpFatalErrorMessageFilter ( 410 _In_ NTSTATUS ErrorStatus, 411 _Out_ PULONG ErrorResourceId 412 ) 413 { 414 ULONG Result; 415 416 /* Assume no message for now, check for known status message */ 417 Result = 0; 418 switch (ErrorStatus) 419 { 420 /* Convert each status to a resource ID */ 421 case STATUS_UNEXPECTED_IO_ERROR: 422 *ErrorResourceId = 9017; 423 Result = 1; 424 break; 425 case STATUS_IMAGE_CHECKSUM_MISMATCH: 426 *ErrorResourceId = 9018; 427 break; 428 case STATUS_INVALID_IMAGE_WIN_64: 429 *ErrorResourceId = 9016; 430 break; 431 case 0xC0000428: 432 *ErrorResourceId = 9019; 433 Result = 2; 434 break; 435 case STATUS_FVE_LOCKED_VOLUME: 436 *ErrorResourceId = 9013; 437 break; 438 } 439 440 /* Return the type of message */ 441 return Result; 442 } 443 444 VOID 445 BmErrorPurge ( 446 VOID 447 ) 448 { 449 /* Check if a boot error is present */ 450 if (BmpPackedBootError.BootError) 451 { 452 /* Purge it */ 453 BlMmFreeHeap(BmpPackedBootError.BootError); 454 BmpPackedBootError.BootError = NULL; 455 } 456 457 /* Zero out the packed buffer */ 458 BmpPackedBootError.Size = 0; 459 BmpInternalBootError = NULL; 460 RtlZeroMemory(&BmpErrorBuffer, sizeof(BmpErrorBuffer)); 461 } 462 463 VOID 464 BmpErrorLog ( 465 _In_ ULONG ErrorCode, 466 _In_ NTSTATUS ErrorStatus, 467 _In_ ULONG ErrorMsgId, 468 _In_ PWCHAR FileName, 469 _In_ ULONG HelpMsgId 470 ) 471 { 472 PWCHAR ErrorMsgString; 473 474 /* Check if we already had an error */ 475 if (BmpInternalBootError) 476 { 477 /* Purge it */ 478 BmErrorPurge(); 479 } 480 481 /* Find the string for this error ID */ 482 ErrorMsgString = BlResourceFindMessage(ErrorMsgId); 483 if (ErrorMsgString) 484 { 485 /* Fill out the error buffer */ 486 BmpErrorBuffer.Unknown1 = 0; 487 BmpErrorBuffer.Unknown2 = 0; 488 BmpErrorBuffer.ErrorString = ErrorMsgString; 489 BmpErrorBuffer.FileName = FileName; 490 BmpErrorBuffer.ErrorCode = ErrorCode; 491 BmpErrorBuffer.ErrorStatus = ErrorStatus; 492 BmpErrorBuffer.HelpMsgId = HelpMsgId; 493 BmpInternalBootError = &BmpErrorBuffer; 494 } 495 } 496 497 VOID 498 BmFatalErrorEx ( 499 _In_ ULONG ErrorCode, 500 _In_ ULONG_PTR Parameter1, 501 _In_ ULONG_PTR Parameter2, 502 _In_ ULONG_PTR Parameter3, 503 _In_ ULONG_PTR Parameter4 504 ) 505 { 506 PWCHAR FileName, Buffer; 507 NTSTATUS ErrorStatus; 508 WCHAR FormatString[256]; 509 ULONG ErrorResourceId, ErrorHelpId; 510 BOOLEAN Restart, NoError; 511 512 /* Assume no buffer for now */ 513 Buffer = NULL; 514 515 /* Check what error code is being raised */ 516 switch (ErrorCode) 517 { 518 /* Error reading the BCD */ 519 case BL_FATAL_ERROR_BCD_READ: 520 521 /* Check if we have a name for the BCD file */ 522 if (Parameter1) 523 { 524 /* Check if the name fits into our buffer */ 525 FileName = (PWCHAR)Parameter1; 526 if (wcslen(FileName) < sizeof(BmpFileNameBuffer)) 527 { 528 /* Copy it in there */ 529 Buffer = BmpFileNameBuffer; 530 wcsncpy(BmpFileNameBuffer, 531 FileName, 532 RTL_NUMBER_OF(BmpFileNameBuffer)); 533 } 534 } 535 536 /* If we don't have a buffer, use an empty one */ 537 if (!Buffer) 538 { 539 Buffer = ParentFileName; 540 } 541 542 /* The NTSTATUS code is in parameter 2*/ 543 ErrorStatus = (NTSTATUS)Parameter2; 544 545 /* Build the error string */ 546 swprintf(FormatString, 547 L"\nAn error occurred (%08x) while attempting " 548 L"to read the boot configuration data file %s\n", 549 ErrorStatus, 550 Buffer); 551 552 /* Select the resource ID message */ 553 ErrorResourceId = 9002; 554 break; 555 556 case BL_FATAL_ERROR_BCD_ENTRIES: 557 558 /* File name is in parameter 1 */ 559 FileName = (PWCHAR)Parameter1; 560 561 /* The NTSTATUS code is in parameter 2*/ 562 ErrorStatus = (NTSTATUS)Parameter2; 563 564 /* Build the error string */ 565 swprintf(FormatString, 566 L"\nNo valid entries found in the boot configuration data file %s\n", 567 FileName); 568 569 /* Select the resource ID message */ 570 ErrorResourceId = 9007; 571 break; 572 573 case BL_FATAL_ERROR_BCD_PARSE: 574 575 /* File name isin parameter 1 */ 576 FileName = (PWCHAR)Parameter1; 577 578 /* The NTSTATUS code is in parameter 2*/ 579 ErrorStatus = (NTSTATUS)Parameter2; 580 581 /* Build the error string */ 582 swprintf(FormatString, 583 L"\nThe boot configuration file %s is invalid (%08x).\n", 584 FileName, 585 ErrorStatus); 586 587 /* Select the resource ID message */ 588 ErrorResourceId = 9015; 589 break; 590 591 case BL_FATAL_ERROR_GENERIC: 592 593 /* The NTSTATUS code is in parameter 1*/ 594 ErrorStatus = (NTSTATUS)Parameter1; 595 596 /* Build the error string */ 597 swprintf(FormatString, 598 L"\nThe boot manager experienced an error (%08x).\n", 599 ErrorStatus); 600 601 /* Select the resource ID message */ 602 ErrorResourceId = 9005; 603 break; 604 605 default: 606 607 /* The rest is not yet handled */ 608 EfiPrintf(L"Unexpected fatal error: %lx\r\n", ErrorCode); 609 while (1); 610 break; 611 } 612 613 /* Check if the BCD option for restart is set */ 614 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 615 BcdLibraryBoolean_RestartOnFailure, 616 &Restart); 617 if (Restart) 618 { 619 /* Yes, so no error should be shown since we'll auto-restart */ 620 NoError = TRUE; 621 } 622 else 623 { 624 /* Check if the option for not showing errors is set in the BCD */ 625 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 626 BcdBootMgrBoolean_NoErrorDisplay, 627 &NoError); 628 } 629 630 /* Do we want an error? */ 631 if (!NoError) 632 { 633 /* Yep, print it and then raise an error */ 634 BlStatusPrint(FormatString); 635 BlStatusError(1, ErrorCode, Parameter1, Parameter2, Parameter3); 636 } 637 638 /* Get the help message ID */ 639 ErrorHelpId = BmpFatalErrorMessageFilter(ErrorStatus, &ErrorResourceId); 640 BmpErrorLog(ErrorCode, ErrorStatus, ErrorResourceId, Buffer, ErrorHelpId); 641 } 642 643 NTSTATUS 644 BmpFwGetFullPath ( 645 _In_ PWCHAR FileName, 646 _Out_ PWCHAR* FullPath 647 ) 648 { 649 NTSTATUS Status; 650 SIZE_T BootDirLength, PathLength; 651 652 /* Compute the length of the directory, and add a NUL */ 653 BootDirLength = wcslen(BootDirectory); 654 Status = RtlSIZETAdd(BootDirLength, 1, &BootDirLength); 655 if (!NT_SUCCESS(Status)) 656 { 657 goto Quickie; 658 } 659 660 /* Add the length of the file, make sure it fits */ 661 PathLength = wcslen(FileName); 662 Status = RtlSIZETAdd(PathLength, BootDirLength, &PathLength); 663 if (!NT_SUCCESS(Status)) 664 { 665 goto Quickie; 666 } 667 668 /* Convert to bytes */ 669 Status = RtlSIZETMult(PathLength, sizeof(WCHAR), &PathLength); 670 if (!NT_SUCCESS(Status)) 671 { 672 goto Quickie; 673 } 674 675 /* Allocate the full path */ 676 *FullPath = BlMmAllocateHeap(PathLength); 677 if (*FullPath) 678 { 679 /* Copy the directory followed by the file name */ 680 wcsncpy(*FullPath, BootDirectory, PathLength / sizeof(WCHAR)); 681 wcsncat(*FullPath, FileName, PathLength / sizeof(WCHAR)); 682 } 683 else 684 { 685 /* Bail out since we have no memory */ 686 Status = STATUS_NO_MEMORY; 687 } 688 689 Quickie: 690 /* Return to caller */ 691 return Status; 692 } 693 694 VOID 695 BmCloseDataStore ( 696 _In_ HANDLE Handle 697 ) 698 { 699 /* Check if boot.ini data needs to be freed */ 700 if (BmBootIniUsed) 701 { 702 EfiPrintf(L"Boot.ini not handled\r\n"); 703 } 704 705 /* Dereference the hive and close the key */ 706 BiDereferenceHive(Handle); 707 BiCloseKey(Handle); 708 } 709 710 NTSTATUS 711 BmOpenDataStore ( 712 _Out_ PHANDLE Handle 713 ) 714 { 715 NTSTATUS Status; 716 PBL_DEVICE_DESCRIPTOR BcdDevice; 717 PWCHAR BcdPath, FullPath, PathBuffer; 718 BOOLEAN HavePath; 719 SIZE_T PathLength, FullSize; 720 PVOID FinalBuffer; 721 UNICODE_STRING BcdString; 722 723 /* Initialize variables */ 724 PathBuffer = NULL; 725 BcdDevice = NULL; 726 BcdPath = NULL; 727 HavePath = FALSE; 728 729 /* Check if a boot.ini file exists */ 730 Status = BmOpenBootIni(); 731 if (NT_SUCCESS(Status)) 732 { 733 BmBootIniUsed = TRUE; 734 } 735 736 /* Check on which device the BCD is */ 737 Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData, 738 BcdBootMgrDevice_BcdDevice, 739 &BcdDevice, 740 NULL); 741 if (!NT_SUCCESS(Status)) 742 { 743 /* It's not on a custom device, so it must be where we are */ 744 Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData, 745 BcdLibraryDevice_ApplicationDevice, 746 &BcdDevice, 747 NULL); 748 if (!NT_SUCCESS(Status)) 749 { 750 /* This BCD option is required */ 751 goto Quickie; 752 } 753 } 754 755 /* Next, check what file contains the BCD */ 756 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData, 757 BcdBootMgrString_BcdFilePath, 758 &BcdPath); 759 if (NT_SUCCESS(Status)) 760 { 761 /* We don't handle custom BCDs yet */ 762 EfiPrintf(L"Custom BCD Not handled: %s\r\n", BcdPath); 763 Status = STATUS_NOT_IMPLEMENTED; 764 goto Quickie; 765 } 766 767 /* Now check if the BCD is on a remote share */ 768 if (BcdDevice->DeviceType == UdpDevice) 769 { 770 /* Nope. Nope. Nope */ 771 EfiPrintf(L"UDP device Not handled\r\n"); 772 Status = STATUS_NOT_IMPLEMENTED; 773 goto Quickie; 774 } 775 776 /* Otherwise, compute the hardcoded path of the BCD */ 777 Status = BmpFwGetFullPath(L"\\BCD", &FullPath); 778 if (!NT_SUCCESS(Status)) 779 { 780 /* User the raw path */ 781 PathBuffer = BcdPath; 782 } 783 else 784 { 785 /* Use the path we got */ 786 PathBuffer = FullPath; 787 HavePath = TRUE; 788 } 789 790 /* Check if we failed to get the BCD path */ 791 if (!NT_SUCCESS(Status)) 792 { 793 goto Quickie; 794 } 795 796 /* Add a NUL to the path, make sure it'll fit */ 797 PathLength = wcslen(PathBuffer); 798 Status = RtlSIZETAdd(PathLength, 1, &PathLength); 799 if (!NT_SUCCESS(Status)) 800 { 801 goto Quickie; 802 } 803 804 /* Convert to bytes */ 805 Status = RtlSIZETMult(PathLength, sizeof(WCHAR), &PathLength); 806 if (!NT_SUCCESS(Status)) 807 { 808 goto Quickie; 809 } 810 811 /* Now add the size of the path to the device path, check if it fits */ 812 Status = RtlSIZETAdd(PathLength, BcdDevice->Size, &FullSize); 813 if (!NT_SUCCESS(Status)) 814 { 815 goto Quickie; 816 } 817 818 /* Allocate a final structure to hold both entities */ 819 FinalBuffer = BlMmAllocateHeap(FullSize); 820 if (!FinalBuffer) 821 { 822 Status = STATUS_NO_MEMORY; 823 goto Quickie; 824 } 825 826 /* Copy the device path and file path into the final buffer */ 827 RtlCopyMemory(FinalBuffer, BcdDevice, BcdDevice->Size); 828 RtlCopyMemory((PVOID)((ULONG_PTR)FinalBuffer + BcdDevice->Size), 829 PathBuffer, 830 PathLength); 831 832 /* Now tell the BCD engine to open the store */ 833 BcdString.Length = FullSize; 834 BcdString.MaximumLength = FullSize; 835 BcdString.Buffer = FinalBuffer; 836 Status = BcdOpenStoreFromFile(&BcdString, Handle); 837 838 /* Free our final buffer */ 839 BlMmFreeHeap(FinalBuffer); 840 841 Quickie: 842 /* Did we allocate a device? */ 843 if (BcdDevice) 844 { 845 /* Free it */ 846 BlMmFreeHeap(BcdDevice); 847 } 848 849 /* Is this the failure path? */ 850 if (!NT_SUCCESS(Status)) 851 { 852 /* Raise a fatal error */ 853 BmFatalErrorEx(BL_FATAL_ERROR_BCD_READ, 854 (ULONG_PTR)PathBuffer, 855 Status, 856 0, 857 0); 858 } 859 860 /* Did we get an allocated path? */ 861 if ((PathBuffer) && (HavePath)) 862 { 863 /* Free it */ 864 BlMmFreeHeap(PathBuffer); 865 } 866 867 /* Return back to the caller */ 868 return Status; 869 } 870 871 typedef struct _BL_BSD_LOG_OBJECT 872 { 873 ULONG DeviceId; 874 ULONG FileId; 875 ULONG Unknown; 876 ULONG Size; 877 ULONG Flags; 878 } BL_BSD_LOG_OBJECT, *PBL_BSD_LOG_OBJECT; 879 880 BL_BSD_LOG_OBJECT BsdpLogObject; 881 BOOLEAN BsdpLogObjectInitialized; 882 883 VOID 884 BlBsdInitializeLog ( 885 _In_ PBL_DEVICE_DESCRIPTOR LogDevice, 886 _In_ PWCHAR LogPath, 887 _In_ ULONG Flags 888 ) 889 { 890 NTSTATUS Status; 891 892 /* Don't initialize twice */ 893 if (BsdpLogObjectInitialized) 894 { 895 return; 896 } 897 898 /* Set invalid IDs for now */ 899 BsdpLogObject.DeviceId = -1; 900 BsdpLogObject.FileId = -1; 901 902 /* Open the BSD device */ 903 Status = BlpDeviceOpen(LogDevice, 904 BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS, 905 0, 906 &BsdpLogObject.DeviceId); 907 if (!NT_SUCCESS(Status)) 908 { 909 /* Welp that didn't work */ 910 goto FailurePath; 911 } 912 913 /* Now open the BSD itself */ 914 Status = BlFileOpen(BsdpLogObject.DeviceId, 915 LogPath, 916 BL_FILE_READ_ACCESS | BL_FILE_WRITE_ACCESS, 917 &BsdpLogObject.FileId); 918 if (!NT_SUCCESS(Status)) 919 { 920 /* D'oh */ 921 goto FailurePath; 922 } 923 924 /* The BSD is open. Start doing stuff to it */ 925 EfiPrintf(L"Unimplemented BSD path\r\n"); 926 Status = STATUS_NOT_IMPLEMENTED; 927 928 FailurePath: 929 /* Close the BSD if we had it open */ 930 if (BsdpLogObject.FileId != -1) 931 { 932 BlFileClose(BsdpLogObject.FileId); 933 } 934 935 /* Close the device if we had it open */ 936 if (BsdpLogObject.DeviceId != -1) 937 { 938 BlDeviceClose(BsdpLogObject.DeviceId); 939 } 940 941 /* Set BSD object to its uninitialized state */ 942 BsdpLogObjectInitialized = FALSE; 943 BsdpLogObject.FileId = 0; 944 BsdpLogObject.DeviceId = 0; 945 BsdpLogObject.Flags = 0; 946 BsdpLogObject.Unknown = 0; 947 BsdpLogObject.Size = 0; 948 } 949 950 VOID 951 BmpInitializeBootStatusDataLog ( 952 VOID 953 ) 954 { 955 NTSTATUS Status; 956 PBL_DEVICE_DESCRIPTOR BsdDevice; 957 PWCHAR BsdPath; 958 ULONG Flags; 959 BOOLEAN PreserveBsd; 960 961 /* Initialize locals */ 962 BsdPath = NULL; 963 BsdDevice = NULL; 964 Flags = 0; 965 966 /* Check if the BSD is stored in a custom device */ 967 Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData, 968 BcdLibraryDevice_BsdLogDevice, 969 &BsdDevice, 970 NULL); 971 if (!NT_SUCCESS(Status)) 972 { 973 /* Nope, use the boot device */ 974 BsdDevice = BlpBootDevice; 975 } 976 977 /* Check if the path is custom as well */ 978 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData, 979 BcdLibraryString_BsdLogPath, 980 &BsdPath); 981 if (!NT_SUCCESS(Status)) 982 { 983 /* Nope, use our default path */ 984 Status = BmpFwGetFullPath(L"\\bootstat.dat", &BsdPath); 985 if (!NT_SUCCESS(Status)) 986 { 987 BsdPath = NULL; 988 } 989 990 /* Set preserve flag */ 991 Flags = 1; 992 } 993 else 994 { 995 /* Set preserve flag */ 996 Flags = 1; 997 } 998 999 /* Finally, check if the BSD should be preserved */ 1000 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 1001 BcdLibraryBoolean_PreserveBsdLog, 1002 &PreserveBsd); 1003 if (!(NT_SUCCESS(Status)) || !(PreserveBsd)) 1004 { 1005 /* We failed to read, or we were asked not to preserve it */ 1006 Flags = 0; 1007 } 1008 1009 /* Initialize the log */ 1010 BlBsdInitializeLog(BsdDevice, BsdPath, Flags); 1011 1012 /* Free the BSD device descriptor if we had one */ 1013 if (BsdDevice) 1014 { 1015 BlMmFreeHeap(BsdDevice); 1016 } 1017 1018 /* Free the BSD path if we had one */ 1019 if ((Flags) && (BsdPath)) 1020 { 1021 BlMmFreeHeap(BsdPath); 1022 } 1023 } 1024 1025 VOID 1026 BmFwMemoryInitialize ( 1027 VOID 1028 ) 1029 { 1030 NTSTATUS Status; 1031 PHYSICAL_ADDRESS PhysicalAddress; 1032 BL_ADDRESS_RANGE AddressRange; 1033 1034 /* Select the range below 1MB */ 1035 AddressRange.Maximum = 0xFFFFF; 1036 AddressRange.Minimum = 0; 1037 1038 /* Allocate one reserved page with the "below 1MB" attribute */ 1039 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress, 1040 BlApplicationReserved, 1041 1, 1042 BlMemoryBelow1MB, 1043 0, 1044 &MmMdlUnmappedAllocated, 1045 &AddressRange, 1046 BL_MM_REQUEST_DEFAULT_TYPE); 1047 if (!NT_SUCCESS(Status)) 1048 { 1049 /* Print a message on error, but keep going */ 1050 BlStatusPrint(L"BmFwMemoryInitialize: Failed to allocate a page below 1MB. Status: 0x%08x\r\n", 1051 Status); 1052 } 1053 } 1054 1055 NTSTATUS 1056 BmpBgDisplayClearScreen ( 1057 _In_ ULONG Color 1058 ) 1059 { 1060 /* Not yet supported */ 1061 return STATUS_NOT_IMPLEMENTED; 1062 } 1063 1064 NTSTATUS 1065 BlXmiWrite ( 1066 _In_ PWCHAR XmlTag 1067 ) 1068 { 1069 /* Sigh */ 1070 EfiPrintf(L"XML: %s\r\n", XmlTag); 1071 return STATUS_NOT_IMPLEMENTED; 1072 } 1073 1074 NTSTATUS 1075 BlXmiInitialize ( 1076 _In_ PWCHAR Stylesheet 1077 ) 1078 { 1079 /* Reset the cursor type */ 1080 BlDisplaySetCursorType(0); 1081 1082 /* Nope, not doing any XML stuff */ 1083 return STATUS_SUCCESS; 1084 } 1085 1086 NTSTATUS 1087 BmFwVerifySelfIntegrity ( 1088 VOID 1089 ) 1090 { 1091 /* Check if we're booted by UEFI off the DVD directly */ 1092 if ((BlpBootDevice->DeviceType == LocalDevice) && 1093 (BlpBootDevice->Local.Type == CdRomDevice) && 1094 (BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI)) 1095 { 1096 /* Windows actually bypasses integrity checks in this case. Works for us */ 1097 return STATUS_SUCCESS; 1098 } 1099 1100 /* Our binaries aren't signed, so always return failure */ 1101 return 0xC0000428; 1102 } 1103 1104 NTSTATUS 1105 BmFwRegisterRevocationList ( 1106 VOID 1107 ) 1108 { 1109 NTSTATUS Status; 1110 BOOLEAN SecureBootEnabled; 1111 1112 /* Is SecureBoot enabled? */ 1113 Status = BlSecureBootIsEnabled(&SecureBootEnabled); 1114 if ((NT_SUCCESS(Status)) && (SecureBootEnabled)) 1115 { 1116 EfiPrintf(L"SB not implemented revok\r\n"); 1117 return STATUS_NOT_IMPLEMENTED; 1118 } 1119 else 1120 { 1121 /* Nothing to do without SecureBoot */ 1122 Status = STATUS_SUCCESS; 1123 } 1124 1125 /* Return revocation result back to caller */ 1126 return Status; 1127 } 1128 1129 NTSTATUS 1130 BmResumeFromHibernate ( 1131 _Out_ PHANDLE BcdResumeHandle 1132 ) 1133 { 1134 NTSTATUS Status; 1135 BOOLEAN AttemptResume; 1136 1137 /* Should we attempt to resume from hibernation? */ 1138 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 1139 BcdBootMgrBoolean_AttemptResume, 1140 &AttemptResume); 1141 if (!NT_SUCCESS(Status)) 1142 { 1143 /* Nope. Is automatic restart on crash enabled? */ 1144 AttemptResume = FALSE; 1145 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 1146 BcdOSLoaderBoolean_DisableCrashAutoReboot, 1147 &AttemptResume); 1148 AttemptResume = (NT_SUCCESS(Status) && (AttemptResume)); 1149 } 1150 1151 /* Don't do anything if there's no need to resume anything */ 1152 if (!AttemptResume) 1153 { 1154 return STATUS_SUCCESS; 1155 } 1156 1157 /* Not yet implemented */ 1158 EfiPrintf(L"Resume not supported\r\n"); 1159 return STATUS_NOT_IMPLEMENTED; 1160 } 1161 1162 NTSTATUS 1163 BmpProcessBadMemory ( 1164 VOID 1165 ) 1166 { 1167 BL_PD_DATA_BLOB BadMemoryData; 1168 NTSTATUS Status; 1169 1170 /* Try to get the memory data from the memtest application */ 1171 BadMemoryData.BlobSize = 0; 1172 BadMemoryData.Data = NULL; 1173 BadMemoryData.DataSize = 0; 1174 Status = BlPdQueryData(&BadMemoryGuid, NULL, &BadMemoryData); 1175 if (Status != STATUS_BUFFER_TOO_SMALL) 1176 { 1177 /* No results, or some other error */ 1178 return Status; 1179 } 1180 1181 /* Not yet implemented */ 1182 EfiPrintf(L"Bad page list persistence not implemented\r\n"); 1183 return STATUS_NOT_IMPLEMENTED; 1184 } 1185 1186 NTSTATUS 1187 BmPurgeOption ( 1188 _In_ HANDLE BcdHandle, 1189 _In_ PGUID ObjectId, 1190 _In_ ULONG Type 1191 ) 1192 { 1193 HANDLE ObjectHandle; 1194 NTSTATUS Status; 1195 1196 /* Open the object */ 1197 Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle); 1198 if (NT_SUCCESS(Status)) 1199 { 1200 /* Delete the element */ 1201 BcdDeleteElement(ObjectHandle, Type); 1202 1203 /* Close the object and set success */ 1204 BiCloseKey(ObjectHandle); 1205 Status = STATUS_SUCCESS; 1206 } 1207 1208 /* Return the result */ 1209 return Status; 1210 } 1211 1212 NTSTATUS 1213 BmGetEntryDescription ( 1214 _In_ HANDLE BcdHandle, 1215 _In_ PGUID ObjectId, 1216 _Out_ PBCD_OBJECT_DESCRIPTION Description 1217 ) 1218 { 1219 NTSTATUS Status; 1220 HANDLE ObjectHandle; 1221 1222 /* Open the BCD object */ 1223 Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle); 1224 if (NT_SUCCESS(Status)) 1225 { 1226 /* Make sure the caller passed this argument in */ 1227 if (!Description) 1228 { 1229 /* Fail otherwise */ 1230 Status = STATUS_INVALID_PARAMETER; 1231 } 1232 else 1233 { 1234 /* Query the description from the BCD interface */ 1235 Status = BiGetObjectDescription(ObjectHandle, Description); 1236 } 1237 1238 /* Close the object key */ 1239 BiCloseKey(ObjectHandle); 1240 } 1241 1242 /* Return the result back */ 1243 return Status; 1244 } 1245 1246 NTSTATUS 1247 BmpPopulateBootEntryList ( 1248 _In_ HANDLE BcdHandle, 1249 _In_ PGUID SequenceList, 1250 _In_ ULONG Flags, 1251 _Out_ PBL_LOADED_APPLICATION_ENTRY* BootSequence, 1252 _Out_ PULONG SequenceCount 1253 ) 1254 { 1255 NTSTATUS Status; 1256 ULONG BootIndex, i, OptionSize; 1257 PBL_LOADED_APPLICATION_ENTRY BootEntry; 1258 PBL_BCD_OPTION Options; 1259 BCD_OBJECT_DESCRIPTION Description; 1260 BcdObjectType ObjectType; 1261 BOOLEAN HavePath, IsWinPe, SoftReboot; 1262 PWCHAR LoaderPath; 1263 1264 /* Initialize locals */ 1265 Options = NULL; 1266 BootIndex = 0; 1267 Status = STATUS_NOT_FOUND; 1268 1269 /* Loop through every element in the sequence */ 1270 for (i = 0; i < *SequenceCount; i++) 1271 { 1272 /* Assume failure */ 1273 BootEntry = NULL; 1274 1275 /* Get the options for the sequence element */ 1276 Status = BmGetOptionList(BcdHandle, SequenceList, &Options); 1277 if (!NT_SUCCESS(Status)) 1278 { 1279 EfiPrintf(L"option list failed: %lx\r\n", Status); 1280 goto LoopQuickie; 1281 } 1282 1283 /* Make sure there's at least a path and description */ 1284 if (!(MiscGetBootOption(Options, BcdLibraryDevice_ApplicationDevice)) || 1285 !(MiscGetBootOption(Options, BcdLibraryString_Description))) 1286 { 1287 Status = STATUS_UNSUCCESSFUL; 1288 EfiPrintf(L"missing list failed: %lx\r\n", Status); 1289 goto LoopQuickie; 1290 } 1291 1292 /* Get the size of the BCD options and allocate a large enough entry */ 1293 OptionSize = BlGetBootOptionListSize(Options); 1294 BootEntry = BlMmAllocateHeap(sizeof(*BootEntry) + OptionSize); 1295 if (!BootEntry) 1296 { 1297 Status = STATUS_NO_MEMORY; 1298 goto Quickie; 1299 } 1300 1301 /* Save it as part of the sequence */ 1302 BootSequence[BootIndex] = BootEntry; 1303 1304 /* Initialize it, and copy the BCD data */ 1305 RtlZeroMemory(BootEntry, sizeof(*BootEntry)); 1306 BootEntry->Guid = *SequenceList; 1307 BootEntry->BcdData = (PBL_BCD_OPTION)(BootEntry + 1); 1308 BootEntry->Flags = Flags; 1309 RtlCopyMemory(BootEntry->BcdData, Options, OptionSize); 1310 1311 /* Get the object descriptor to find out what kind of entry it is */ 1312 Status = BmGetEntryDescription(BcdHandle, 1313 &BootEntry->Guid, 1314 &Description); 1315 if (!NT_SUCCESS(Status)) 1316 { 1317 EfiPrintf(L"missing desc failed: %lx\r\n", Status); 1318 goto LoopQuickie; 1319 } 1320 1321 /* Check if a path was given or not */ 1322 HavePath = MiscGetBootOption(Options, BcdLibraryString_ApplicationPath) ? 1323 TRUE : FALSE; 1324 1325 /* Now select based on what type of object this is -- must be an app */ 1326 ObjectType.PackedValue = Description.Type; 1327 if (ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION) 1328 { 1329 /* Then select based on what kind of app it is */ 1330 switch (ObjectType.Application.ApplicationCode) 1331 { 1332 /* Another boot manager */ 1333 case BCD_APPLICATION_TYPE_BOOTMGR: 1334 BootEntry->Flags |= BCD_APPLICATION_TYPE_BOOTMGR; 1335 break; 1336 1337 /* An OS loader */ 1338 case BCD_APPLICATION_TYPE_OSLOADER: 1339 BootEntry->Flags |= BL_APPLICATION_ENTRY_WINLOAD; 1340 1341 /* Do we have a path for it? */ 1342 if (!HavePath) 1343 { 1344 /* We'll try to make one up. Is this WinPE? */ 1345 IsWinPe = FALSE; 1346 Status = BlGetBootOptionBoolean(Options, 1347 BcdOSLoaderBoolean_WinPEMode, 1348 &IsWinPe); 1349 if (!(NT_SUCCESS(Status)) && (Status != STATUS_NOT_FOUND)) 1350 { 1351 goto Quickie; 1352 } 1353 1354 /* Use the appropriate path for WinPE or local install */ 1355 LoaderPath = IsWinPe ? 1356 L"\\Windows\\System32\\boot\\winload.efi" : 1357 L"\\Windows\\System32\\winload.efi"; 1358 1359 /* Add the path to the boot entry */ 1360 Status = BlAppendBootOptionString(BootEntry, 1361 BcdLibraryString_ApplicationPath, 1362 LoaderPath); 1363 if (!NT_SUCCESS(Status)) 1364 { 1365 goto Quickie; 1366 } 1367 1368 /* We have a path now */ 1369 HavePath = TRUE; 1370 } 1371 break; 1372 1373 /* A hibernate-resume application */ 1374 case BCD_APPLICATION_TYPE_RESUME: 1375 BootEntry->Flags |= BL_APPLICATION_ENTRY_WINRESUME; 1376 break; 1377 1378 /* An older OS NTLDR */ 1379 case BCD_APPLICATION_TYPE_NTLDR: 1380 BootEntry->Flags |= BL_APPLICATION_ENTRY_NTLDR; 1381 break; 1382 1383 /* An older OS SETUPLDR */ 1384 case BCD_APPLICATION_TYPE_SETUPLDR: 1385 BootEntry->Flags |= BL_APPLICATION_ENTRY_SETUPLDR; 1386 break; 1387 1388 /* A 3rd party/Win9x boot sector */ 1389 case BCD_APPLICATION_TYPE_BOOTSECTOR: 1390 BootEntry->Flags |= BL_APPLICATION_ENTRY_BOOTSECTOR; 1391 break; 1392 1393 /* Something else entirely */ 1394 default: 1395 break; 1396 } 1397 } 1398 1399 /* We better have a path by now */ 1400 if (!HavePath) 1401 { 1402 Status = STATUS_UNSUCCESSFUL; 1403 goto LoopQuickie; 1404 } 1405 1406 /* Check if this is a real mode startup.com */ 1407 if ((ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION) && 1408 (ObjectType.Application.ImageCode == BCD_IMAGE_TYPE_REAL_MODE) && 1409 (ObjectType.Application.ApplicationCode == BCD_APPLICATION_TYPE_STARTUPCOM)) 1410 { 1411 /* Check if PXE soft reboot will occur */ 1412 Status = BlGetBootOptionBoolean(Options, 1413 BcdStartupBoolean_PxeSoftReboot, 1414 &SoftReboot); 1415 if ((NT_SUCCESS(Status)) && (SoftReboot)) 1416 { 1417 /* Then it's a valid startup.com entry */ 1418 BootEntry->Flags |= BL_APPLICATION_ENTRY_STARTUP; 1419 } 1420 } 1421 1422 LoopQuickie: 1423 /* All done with this entry -- did we have BCD options? */ 1424 if (Options) 1425 { 1426 /* Free them, they're part of the entry now */ 1427 BlMmFreeHeap(Options); 1428 Options = NULL; 1429 } 1430 1431 /* Did we fail anywhere? */ 1432 if (!NT_SUCCESS(Status)) 1433 { 1434 /* Yep -- did we fail with an active boot entry? */ 1435 if (BootEntry) 1436 { 1437 /* Destroy it */ 1438 BlDestroyBootEntry(BootEntry); 1439 BootSequence[BootIndex] = NULL; 1440 } 1441 } 1442 else 1443 { 1444 /* It worked, so populate the next index now */ 1445 BootIndex++; 1446 } 1447 1448 /* And move to the next GUID in the sequence list */ 1449 SequenceList++; 1450 } 1451 1452 Quickie: 1453 /* All done now -- did we have any BCD options? */ 1454 if (Options) 1455 { 1456 /* Free them */ 1457 BlMmFreeHeap(Options); 1458 } 1459 1460 /* Return the status */ 1461 return Status; 1462 } 1463 1464 NTSTATUS 1465 BmGetBootSequence ( 1466 _In_ HANDLE BcdHandle, 1467 _In_ PGUID SequenceList, 1468 _In_ ULONG SequenceListCount, 1469 _In_ ULONG Flags, 1470 _Out_ PBL_LOADED_APPLICATION_ENTRY** BootSequence, 1471 _Out_ PULONG SequenceCount 1472 ) 1473 { 1474 PBL_LOADED_APPLICATION_ENTRY* Sequence; 1475 ULONG Count = SequenceListCount; 1476 NTSTATUS Status; 1477 1478 /* Allocate the sequence list */ 1479 Sequence = BlMmAllocateHeap(SequenceListCount * sizeof(*Sequence)); 1480 if (!Sequence) 1481 { 1482 return STATUS_NO_MEMORY; 1483 } 1484 1485 /* Populate the sequence list */ 1486 Status = BmpPopulateBootEntryList(BcdHandle, 1487 SequenceList, 1488 Flags, 1489 Sequence, 1490 &Count); 1491 if (!NT_SUCCESS(Status)) 1492 { 1493 /* Free the list on failure */ 1494 BlMmFreeHeap(Sequence); 1495 } 1496 else 1497 { 1498 /* Otherwise, set success and return the list and count */ 1499 Status = STATUS_SUCCESS; 1500 *BootSequence = Sequence; 1501 *SequenceCount = Count; 1502 } 1503 1504 /* All done */ 1505 return Status; 1506 } 1507 1508 NTSTATUS 1509 BmEnumerateBootEntries ( 1510 _In_ HANDLE BcdHandle, 1511 _Out_ PBL_LOADED_APPLICATION_ENTRY **BootSequence, 1512 _Out_ PULONG SequenceCount 1513 ) 1514 { 1515 NTSTATUS Status; 1516 ULONG BootIndex, BootIniCount, BootEntryCount, BcdCount; 1517 PBL_LOADED_APPLICATION_ENTRY* Sequence; 1518 PGUID DisplayOrder; 1519 GUID DefaultObject; 1520 BOOLEAN UseDisplayList; 1521 1522 /* Initialize locals */ 1523 BootIndex = 0; 1524 1525 /* First try to get the display list, if any */ 1526 UseDisplayList = TRUE; 1527 Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData, 1528 BcdBootMgrObjectList_DisplayOrder, 1529 &DisplayOrder, 1530 &BcdCount); 1531 if (!NT_SUCCESS(Status)) 1532 { 1533 /* No list, get the default entry instead */ 1534 Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData, 1535 BcdBootMgrObject_DefaultObject, 1536 &DefaultObject); 1537 if (NT_SUCCESS(Status)) 1538 { 1539 /* Set the array to just our entry */ 1540 UseDisplayList = FALSE; 1541 BcdCount = 1; 1542 DisplayOrder = &DefaultObject; 1543 } 1544 else 1545 { 1546 /* No default list either, return success but no entries */ 1547 *BootSequence = NULL; 1548 *SequenceCount = 0; 1549 Status = STATUS_SUCCESS; 1550 DisplayOrder = NULL; 1551 goto Quickie; 1552 } 1553 } 1554 1555 /* Check if boot.ini was used */ 1556 BootIniCount = 0; 1557 if (BmBootIniUsed) 1558 { 1559 /* Get the entries from it */ 1560 EfiPrintf(L"Boot.ini not supported\r\n"); 1561 BootIniCount = 0;//BmBootIniGetEntryCount(); 1562 } 1563 1564 /* Allocate an array large enough for the combined boot entries */ 1565 BootEntryCount = BootIniCount + BcdCount; 1566 Sequence = BlMmAllocateHeap(BootEntryCount * sizeof(*Sequence)); 1567 if (!Sequence) 1568 { 1569 Status = STATUS_NO_MEMORY; 1570 goto Quickie; 1571 } 1572 1573 /* Zero it out */ 1574 RtlZeroMemory(Sequence, BootEntryCount * sizeof(*Sequence)); 1575 1576 /* Check if we had BCD entries */ 1577 if (BcdCount) 1578 { 1579 /* Populate the list of bootable entries */ 1580 Status = BmpPopulateBootEntryList(BcdHandle, 1581 DisplayOrder, 1582 BL_APPLICATION_ENTRY_DISPLAY_ORDER, 1583 Sequence, 1584 &BcdCount); 1585 if (!NT_SUCCESS(Status)) 1586 { 1587 /* Bail out */ 1588 goto Quickie; 1589 } 1590 } 1591 1592 /* Check if we had boot.ini entries */ 1593 if (BootIniCount) 1594 { 1595 /* TODO */ 1596 EfiPrintf(L"Boot.ini not supported\r\n"); 1597 } 1598 1599 /* Return success and the sequence + count populated */ 1600 Status = STATUS_SUCCESS; 1601 *BootSequence = Sequence; 1602 *SequenceCount = BootIniCount + BcdCount; 1603 1604 Quickie: 1605 /* Check if we had allocated a GUID list */ 1606 if ((UseDisplayList) && (DisplayOrder)) 1607 { 1608 /* Free it */ 1609 BlMmFreeHeap(DisplayOrder); 1610 } 1611 1612 /* Check if this is the failure path */ 1613 if (!(NT_SUCCESS(Status)) && (Sequence)) 1614 { 1615 /* Loop the remaining boot entries */ 1616 while (BootIndex < BootEntryCount) 1617 { 1618 /* Check if it had been allocated */ 1619 if (Sequence[BootIndex]) 1620 { 1621 /* Free it */ 1622 BlMmFreeHeap(Sequence[BootIndex]); 1623 } 1624 1625 /* Next*/ 1626 BootIndex++; 1627 } 1628 1629 /* Free the whole sequence now */ 1630 BlMmFreeHeap(Sequence); 1631 } 1632 1633 /* All done, return the result */ 1634 return Status; 1635 } 1636 1637 VOID 1638 BmpGetDefaultBootEntry ( 1639 _In_ PBL_LOADED_APPLICATION_ENTRY* Sequence, 1640 _In_ ULONG Count, 1641 _Out_ PBL_LOADED_APPLICATION_ENTRY* DefaultEntry, 1642 _Out_ PULONG DefaultIndex 1643 ) 1644 { 1645 GUID DefaultObject; 1646 NTSTATUS Status; 1647 ULONG BootIndex; 1648 1649 /* Assume no default */ 1650 *DefaultEntry = *Sequence; 1651 *DefaultIndex = 0; 1652 1653 /* Nothing to do if there's just one entry */ 1654 if (Count == 1) 1655 { 1656 return; 1657 } 1658 1659 /* Get the default object, bail out if there isn't one */ 1660 Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData, 1661 BcdBootMgrObject_DefaultObject, 1662 &DefaultObject); 1663 if (!(NT_SUCCESS(Status)) || !(Count)) 1664 { 1665 return; 1666 } 1667 1668 /* Scan the boot sequence */ 1669 for (BootIndex = 0; BootIndex < Count; BootIndex++) 1670 { 1671 /* Find one that matches the default */ 1672 if (RtlEqualMemory(&Sequence[BootIndex]->Guid, 1673 &DefaultObject, 1674 sizeof(GUID))) 1675 { 1676 /* Return it */ 1677 *DefaultEntry = Sequence[BootIndex]; 1678 *DefaultIndex = BootIndex; 1679 return; 1680 } 1681 } 1682 } 1683 1684 BL_MENU_POLICY 1685 BmGetBootMenuPolicy ( 1686 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry 1687 ) 1688 { 1689 NTSTATUS Status; 1690 BOOLEAN EmsEnabled; 1691 ULONGLONG BootMenuPolicy; 1692 ULONG OptionId; 1693 1694 /* Check if EMS is enabled */ 1695 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 1696 BcdOSLoaderBoolean_EmsEnabled, 1697 &EmsEnabled); 1698 if ((NT_SUCCESS(Status)) && (EmsEnabled)) 1699 { 1700 /* No boot menu */ 1701 return MenuPolicyLegacy; 1702 } 1703 1704 /* Check what entry we are looking at */ 1705 if (!BootEntry) 1706 { 1707 /* No entry, pick the selected one */ 1708 BootEntry = BmpSelectedBootEntry; 1709 } 1710 1711 /* Do we still not have an entry? */ 1712 if (!BootEntry) 1713 { 1714 /* Show the menu */ 1715 return MenuPolicyStandard; 1716 } 1717 1718 /* Check if this is an OS loader */ 1719 BootMenuPolicy = 0; 1720 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD) 1721 { 1722 /* Use the correct option ID */ 1723 OptionId = BcdOSLoaderInteger_BootMenuPolicy; 1724 } 1725 else 1726 { 1727 /* Check if this is an OS resumer */ 1728 if (!(BootEntry->Flags & BL_APPLICATION_ENTRY_WINRESUME)) 1729 { 1730 /* Nope, so no reason for a menu */ 1731 return MenuPolicyLegacy; 1732 } 1733 1734 /* Use the correct option ID */ 1735 OptionId = BcdResumeInteger_BootMenuPolicy; 1736 } 1737 1738 /* Check the option ID for the boot menu policy */ 1739 Status = BlGetBootOptionInteger(BootEntry->BcdData, 1740 OptionId, 1741 &BootMenuPolicy); 1742 if (NT_SUCCESS(Status)) 1743 { 1744 /* We have one, return it */ 1745 return BootMenuPolicy; 1746 } 1747 1748 /* No policy, so assume no menu */ 1749 return MenuPolicyLegacy; 1750 } 1751 1752 VOID 1753 BmDisplayGetBootMenuStatus ( 1754 _Out_ PL_MENU_STATUS MenuStatus 1755 ) 1756 { 1757 /* For now, don't support key input at all */ 1758 MenuStatus->AsULong = 0; 1759 MenuStatus->OemKey = UNICODE_NULL; 1760 MenuStatus->BootIndex = -1; 1761 } 1762 1763 NTSTATUS 1764 BmProcessCustomAction ( 1765 _In_ HANDLE BcdHandle, 1766 _In_ PWCHAR ActionKey 1767 ) 1768 { 1769 EfiPrintf(L"Custom actions not yet handled\r\n"); 1770 return STATUS_NOT_IMPLEMENTED; 1771 } 1772 1773 VOID 1774 BmpProcessBootEntry ( 1775 _In_ HANDLE BcdHandle, 1776 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 1777 _Out_ PBOOLEAN ExitBootManager 1778 ) 1779 { 1780 BL_MENU_STATUS MenuStatus; 1781 1782 /* Don't exit */ 1783 *ExitBootManager = FALSE; 1784 1785 /* If the legacy menu must be shown, or if we have a boot entry */ 1786 if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) || (BootEntry)) 1787 { 1788 /* Check if any key has been pressed */ 1789 BmDisplayGetBootMenuStatus(&MenuStatus); 1790 if (MenuStatus.AnyKey) 1791 { 1792 /* Was the exit key pressed? */ 1793 if (MenuStatus.Exit) 1794 { 1795 /* Don't display a menu, and exit */ 1796 *ExitBootManager = TRUE; 1797 BmpDisplayBootMenu = FALSE; 1798 } 1799 else if (MenuStatus.OemKey) 1800 { 1801 /* Process the OEM key action */ 1802 BmProcessCustomAction(BcdHandle, &MenuStatus.KeyValue); 1803 } 1804 else 1805 { 1806 /* Process other keys */ 1807 EfiPrintf(L"TODO\r\n"); 1808 } 1809 } 1810 } 1811 } 1812 1813 NTSTATUS 1814 BmpGetSelectedBootEntry ( 1815 _In_ HANDLE BcdHandle, 1816 _Out_ PBL_LOADED_APPLICATION_ENTRY* SelectedBootEntry, 1817 _Out_ PULONG EntryIndex, 1818 _Out_ PBOOLEAN ExitBootManager 1819 ) 1820 { 1821 NTSTATUS Status; 1822 PBL_LOADED_APPLICATION_ENTRY* Sequence; 1823 PBL_LOADED_APPLICATION_ENTRY Entry, SelectedEntry; 1824 ULONG Count, BootIndex, SelectedIndex; 1825 // BOOLEAN FoundFailedEntry; 1826 ULONGLONG Timeout; 1827 1828 /* Initialize locals */ 1829 BootIndex = 0; 1830 Count = 0; 1831 Sequence = NULL; 1832 SelectedEntry = NULL; 1833 1834 /* Enumerate all the boot entries */ 1835 Status = BmEnumerateBootEntries(BcdHandle, &Sequence, &Count); 1836 if (!NT_SUCCESS(Status)) 1837 { 1838 /* Bail out if we failed */ 1839 goto Quickie; 1840 } 1841 1842 /* Check if there are no entries */ 1843 if (!Count) 1844 { 1845 /* This is fatal -- kill the system */ 1846 Status = STATUS_FILE_INVALID; 1847 BmFatalErrorEx(BL_FATAL_ERROR_BCD_ENTRIES, (ULONG_PTR)L"\\BCD", Status, 0, 0); 1848 goto Quickie; 1849 } 1850 1851 /* Check if we don't yet have an array of failed boot entries */ 1852 if (!BmpFailedBootEntries) 1853 { 1854 /* Allocate it */ 1855 BmpFailedBootEntries = BlMmAllocateHeap(Count); 1856 if (BmpFailedBootEntries) 1857 { 1858 /* Zero it out */ 1859 RtlZeroMemory(BmpFailedBootEntries, Count); 1860 } 1861 } 1862 1863 /* Check if we have a hardcoded boot override */ 1864 if (BmBootEntryOverridePresent) 1865 { 1866 EfiPrintf(L"Hard-coded boot override mode not supported\r\n"); 1867 } 1868 1869 /* Log the OS count */ 1870 //BlLogEtwWrite(BOOT_BOOTMGR_MULTI_OS_COUNT); 1871 1872 /* Check if the display is already active and cached */ 1873 if (!BmDisplayStateCached) 1874 { 1875 /* Check if we should display a boot menu */ 1876 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 1877 BcdBootMgrBoolean_DisplayBootMenu, 1878 &BmpDisplayBootMenu); 1879 if (!NT_SUCCESS(Status)) 1880 { 1881 /* Assume not */ 1882 BmpDisplayBootMenu = FALSE; 1883 } 1884 } 1885 1886 /* Check if there's only one entry to boot anyway */ 1887 if (Count == 1) 1888 { 1889 /* Read it */ 1890 SelectedEntry = *Sequence; 1891 1892 /* Process it */ 1893 BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager); 1894 1895 /* Check if we're not displaying a boot menu */ 1896 if (!BmpDisplayBootMenu) 1897 { 1898 /* Now we are */ 1899 BmpDisplayBootMenu = TRUE; 1900 1901 /* Return the entry and its index back */ 1902 *EntryIndex = 0; 1903 *SelectedBootEntry = SelectedEntry; 1904 Status = STATUS_SUCCESS; 1905 goto Quickie; 1906 } 1907 } 1908 else 1909 { 1910 /* Get the default boot entry */ 1911 BmpGetDefaultBootEntry(Sequence, Count, &SelectedEntry, &SelectedIndex); 1912 1913 /* Check if we have a failed boot entry array allocated */ 1914 //FoundFailedEntry = FALSE; 1915 if (BmpFailedBootEntries) 1916 { 1917 /* Check if the default entry failed to boot */ 1918 if (BmpFailedBootEntries[SelectedIndex]) 1919 { 1920 /* Loop through the current boot sequence */ 1921 for (SelectedIndex = 0; SelectedIndex < Count; SelectedIndex++) 1922 { 1923 /* Check if there's no sequence for this index, or it failed */ 1924 while (!(Sequence[SelectedIndex]) || 1925 (BmpFailedBootEntries[SelectedIndex])) 1926 { 1927 /* Remember that this is a failed entry */ 1928 SelectedEntry = Sequence[SelectedIndex]; 1929 //FoundFailedEntry = TRUE; 1930 BmpDisplayBootMenu = FALSE; 1931 } 1932 } 1933 } 1934 } 1935 1936 /* Check if the entry is an OS loader */ 1937 if (SelectedEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD) 1938 { 1939 // todo 1940 EfiPrintf(L"todo path\r\n"); 1941 } 1942 1943 /* Check if there's no timeout */ 1944 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData, 1945 BcdBootMgrInteger_Timeout, 1946 &Timeout); 1947 if ((NT_SUCCESS(Status) && !(Timeout))) 1948 { 1949 /* There isn't, so just process the default entry right away */ 1950 BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager); 1951 1952 /* Check if we're not displaying a boot menu */ 1953 if (!BmpDisplayBootMenu) 1954 { 1955 /* Now we are */ 1956 BmpDisplayBootMenu = TRUE; 1957 1958 /* Return the entry and its index back */ 1959 *EntryIndex = 0; 1960 *SelectedBootEntry = SelectedEntry; 1961 Status = STATUS_SUCCESS; 1962 goto Quickie; 1963 } 1964 1965 /* Remove the timeout for this boot instance */ 1966 BlRemoveBootOption(BlpApplicationEntry.BcdData, 1967 BcdBootMgrInteger_Timeout); 1968 } 1969 } 1970 1971 /* Here is where we display the menu and list of tools */ 1972 EfiPrintf(L"Tool selection not yet implemented\r\n"); 1973 EfiStall(10000000); 1974 *SelectedBootEntry = NULL; 1975 1976 Quickie: 1977 /* We are done -- did we have a sequence? */ 1978 if (Sequence) 1979 { 1980 /* Do we have any boot entries we parsed? */ 1981 while (BootIndex < Count) 1982 { 1983 /* Get the current boot entry */ 1984 Entry = Sequence[BootIndex]; 1985 1986 /* Did we fail, or is is not the selected one? */ 1987 if ((Entry) && ((Entry != SelectedEntry) || !(NT_SUCCESS(Status)))) 1988 { 1989 /* Destroy it, as it won't be needed */ 1990 BlDestroyBootEntry(Entry); 1991 } 1992 else if (Entry == SelectedEntry) 1993 { 1994 /* It's the selected one, return its index */ 1995 *EntryIndex = BootIndex; 1996 } 1997 1998 /* Move to the next entry */ 1999 BootIndex++; 2000 } 2001 2002 /* Free the sequence of entries */ 2003 BlMmFreeHeap(Sequence); 2004 } 2005 2006 /* Return the selection result */ 2007 return Status; 2008 } 2009 2010 NTSTATUS 2011 BmLaunchRecoverySequence ( 2012 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 2013 _In_ ULONG LaunchCode 2014 ) 2015 { 2016 NTSTATUS Status; 2017 PBL_LOADED_APPLICATION_ENTRY RecoveryEntry; 2018 HANDLE BcdHandle; 2019 PGUID RecoverySequence; 2020 ULONG Count, i, RecoveryIndex, SequenceCount; 2021 PBL_LOADED_APPLICATION_ENTRY* Sequence; 2022 2023 /* Initialize locals */ 2024 RecoveryIndex = 0; 2025 Sequence = NULL; 2026 RecoverySequence = NULL; 2027 Count = 0; 2028 BcdHandle = NULL; 2029 2030 /* Open the BCD*/ 2031 Status = BmOpenDataStore(&BcdHandle); 2032 if (!NT_SUCCESS(Status)) 2033 { 2034 goto Quickie; 2035 } 2036 2037 /* Get the recovery sequence list */ 2038 Status = BlGetBootOptionGuidList(BootEntry->BcdData, 2039 BcdLibraryObjectList_RecoverySequence, 2040 &RecoverySequence, 2041 &SequenceCount); 2042 if (!NT_SUCCESS(Status)) 2043 { 2044 goto Quickie; 2045 } 2046 2047 /* Get the sequence of boot entries out of it */ 2048 Status = BmGetBootSequence(BcdHandle, 2049 RecoverySequence, 2050 SequenceCount, 2051 BL_APPLICATION_ENTRY_RECOVERY, 2052 &Sequence, 2053 &Count); 2054 if (!NT_SUCCESS(Status)) 2055 { 2056 goto Quickie; 2057 } 2058 2059 /* Was the BCD open? */ 2060 if (BcdHandle) 2061 { 2062 /* Close it */ 2063 BmCloseDataStore(BcdHandle); 2064 } 2065 2066 /* Now go over every entry in the sequence */ 2067 for (i = 0; i < Count; ++i) 2068 { 2069 /* Check the code for this recovery launch */ 2070 if (LaunchCode == 2 || LaunchCode == 5) 2071 { 2072 /* Remove the override if there is one, and set it to 4 */ 2073 BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride); 2074 BlAppendBootOptionInteger(Sequence[i], 2075 BcdLibraryInteger_DisplayMessageOverride, 2076 4); 2077 } 2078 else if (LaunchCode == 3) 2079 { 2080 /* Remove the override if there is one, and set it to 10 */ 2081 BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride); 2082 BlAppendBootOptionInteger(Sequence[i], 2083 BcdLibraryInteger_DisplayMessageOverride, 2084 10); 2085 } 2086 2087 /* Launch the boot entry for this part of the recovery sequence */ 2088 Status = BmpLaunchBootEntry(Sequence[i], NULL, LaunchCode, FALSE); 2089 if (!NT_SUCCESS(Status)) 2090 { 2091 break; 2092 } 2093 } 2094 2095 Quickie: 2096 /* Did we have a sequence of entries? */ 2097 if (Sequence) 2098 { 2099 /* Loop through each one */ 2100 for (RecoveryIndex = 0; RecoveryIndex < Count; RecoveryIndex++) 2101 { 2102 /* Does this index have an allocated boot entry? */ 2103 RecoveryEntry = Sequence[RecoveryIndex]; 2104 if (RecoveryEntry) 2105 { 2106 /* Destroy it */ 2107 BlDestroyBootEntry(RecoveryEntry); 2108 } 2109 } 2110 2111 /* Free the sequence itself */ 2112 BlMmFreeHeap(Sequence); 2113 } 2114 2115 /* Was there a sequence list? */ 2116 if (RecoverySequence) 2117 { 2118 /* Free it */ 2119 BlMmFreeHeap(RecoverySequence); 2120 } 2121 2122 /* Return back to caller */ 2123 return Status; 2124 } 2125 2126 ULONG 2127 BmDisplayDumpError ( 2128 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 2129 _In_ ULONG LaunchCode 2130 ) 2131 { 2132 ULONG BootError; 2133 NTSTATUS Status; 2134 BOOLEAN Restart, NoError; 2135 2136 /* Assume we'll just reboot */ 2137 BootError = Reboot; 2138 2139 /* Should we reboot? */ 2140 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 2141 BcdLibraryBoolean_RestartOnFailure, 2142 &Restart); 2143 if ((NT_SUCCESS(Status)) && (Restart)) 2144 { 2145 return BootError; 2146 } 2147 2148 /* Should we not show errors, and thus, reboot? */ 2149 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 2150 BcdBootMgrBoolean_NoErrorDisplay, 2151 &NoError); 2152 if ((NT_SUCCESS(Status)) && (NoError)) 2153 { 2154 return BootError; 2155 } 2156 2157 /* Is there an internal boot error? */ 2158 if (BmpInternalBootError) 2159 { 2160 /* Return it -- but it's a pointer? */ 2161 return (ULONG_PTR)BmpInternalBootError; // ??? 2162 } 2163 2164 /* Otherwise, show the menu to see what to do */ 2165 EfiPrintf(L"Error menu not yet implemented\r\n"); 2166 return BootError; 2167 } 2168 2169 NTSTATUS 2170 BmpCreateDevices ( 2171 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry 2172 ) 2173 { 2174 ULONG NextOffset, DataOffset, ListOffset; 2175 PBL_BCD_OPTION Option, ListOption; 2176 BcdElementType ElementType; 2177 PBCD_DEVICE_OPTION BcdDevice; 2178 2179 /* Starting at offset 0, loop every BCD option */ 2180 NextOffset = 0; 2181 do 2182 { 2183 /* Get the current option, and its offset */ 2184 Option = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + NextOffset); 2185 NextOffset = Option->NextEntryOffset; 2186 2187 /* If it's empty, ignore it */ 2188 if (Option->Empty) 2189 { 2190 continue; 2191 } 2192 2193 /* If it's not a device option, ignore it */ 2194 ElementType.PackedValue = Option->Type; 2195 if (ElementType.Format != BCD_TYPE_DEVICE) 2196 { 2197 continue; 2198 } 2199 2200 /* Get the data offset */ 2201 DataOffset = Option->DataOffset; 2202 2203 /* Extract the device out of it */ 2204 BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)BootEntry->BcdData + DataOffset); 2205 2206 /* If the device is already fully specified, no need to build it */ 2207 if (!(BcdDevice->DeviceDescriptor.Flags & 1)) 2208 { 2209 continue; 2210 } 2211 2212 /* Otherwise, check if there's any list options as well */ 2213 ListOption = NULL; 2214 ListOffset = Option->ListOffset; 2215 if (Option->ListOffset) 2216 { 2217 ListOption = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + ListOffset); 2218 } 2219 2220 /* And now call BlCreateDevice to build the full device descriptor */ 2221 EfiPrintf(L"Unspecified devices not yet supported: %p\r\n", ListOption); 2222 return STATUS_NOT_SUPPORTED; 2223 } while (NextOffset != 0); 2224 2225 /* Devices created successfully */ 2226 return STATUS_SUCCESS; 2227 } 2228 2229 NTSTATUS 2230 BmpTransferExecution ( 2231 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 2232 _Out_ PULONG LaunchCode, 2233 _Out_ PBOOLEAN Recover 2234 ) 2235 { 2236 PWCHAR AppPath; 2237 NTSTATUS Status; 2238 PBL_DEVICE_DESCRIPTOR AppDevice; 2239 BL_RETURN_ARGUMENTS ReturnArgs; 2240 BOOLEAN AdvancedOptions; 2241 ULONG AppHandle; 2242 2243 /* Get the application path */ 2244 Status = BlGetBootOptionString(BootEntry->BcdData, 2245 BcdLibraryString_ApplicationPath, 2246 &AppPath); 2247 if (!NT_SUCCESS(Status)) 2248 { 2249 /* If we couldn't find one, set this to NULL */ 2250 AppPath = NULL; 2251 } 2252 2253 /* Check if this is a PXE startup.com */ 2254 if (BootEntry->Flags & BL_APPLICATION_ENTRY_STARTUP) 2255 { 2256 #if BL_NET_SUPPORT 2257 /* Do soft reboot to launch it */ 2258 Status = BlNetSoftReboot(BootEntry); 2259 #else 2260 EfiPrintf(L"Net boot not supported\r\n"); 2261 Status = STATUS_NOT_SUPPORTED; 2262 #endif 2263 /* Nothing else for us to do */ 2264 goto Quickie; 2265 } 2266 2267 /* Loop as long as boot was not cancelled */ 2268 do 2269 { 2270 /* Load the boot application */ 2271 Status = BlImgLoadBootApplication(BootEntry, &AppHandle); 2272 2273 /* Did we not find it? */ 2274 if (Status == STATUS_NOT_FOUND) 2275 { 2276 /* Get the device for the boot application */ 2277 Status = BlGetBootOptionDevice(BootEntry->BcdData, 2278 BcdLibraryDevice_ApplicationDevice, 2279 &AppDevice, 2280 NULL); 2281 if (!NT_SUCCESS(Status)) 2282 { 2283 /* Force re-enumeration */ 2284 Status = BlFwEnumerateDevice(AppDevice); 2285 } 2286 2287 /* Did re-enumeration work? */ 2288 if (!NT_SUCCESS(Status)) 2289 { 2290 /* Nope, raise a fatal error */ 2291 BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD, 2292 (ULONG_PTR)AppPath, 2293 Status, 2294 0, 2295 0); 2296 goto Quickie; 2297 } 2298 2299 /* Yes, try booting it again */ 2300 Status = BlImgLoadBootApplication(BootEntry, &AppHandle); 2301 } 2302 2303 /* Was boot cancelled?*/ 2304 if (Status == STATUS_CANCELLED) 2305 { 2306 /* Should we display the menu, or is there no launch sequence? */ 2307 if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) || 2308 !(MiscGetBootOption(BootEntry->BcdData, 2309 BcdLibraryObjectList_RecoverySequence))) 2310 { 2311 /* Bail out, the menu will take care of it */ 2312 goto Quickie; 2313 } 2314 2315 /* No menu and there's a sequence, launch it */ 2316 *LaunchCode = 4; 2317 *Recover = TRUE; 2318 goto Quickie; 2319 } 2320 2321 /* STATUS_FVE_LOCKED_VOLUME -- bitlocker volume is locked */ 2322 if (Status == STATUS_FVE_LOCKED_VOLUME) 2323 { 2324 /* Launch recovery mode */ 2325 *LaunchCode = 4; 2326 *Recover = TRUE; 2327 goto Quickie; 2328 } 2329 2330 /* Was there some other error launching the boot application? */ 2331 if (!NT_SUCCESS(Status)) 2332 { 2333 /* Raise a fatal error */ 2334 BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD, 2335 (ULONG_PTR)AppPath, 2336 Status, 2337 0, 2338 0); 2339 goto Quickie; 2340 } 2341 2342 /* Zero out the return arguments */ 2343 RtlZeroMemory(&ReturnArgs, sizeof(ReturnArgs)); 2344 2345 /* Log to ETW this launch */ 2346 //BmpLogApplicationLaunchEvent(&BootEntry->Guid, AppPath); 2347 2348 /* Launch the boot application*/ 2349 Status = BlImgStartBootApplication(AppHandle, &ReturnArgs); 2350 2351 #if BL_BITLOCKER_SUPPORT 2352 /* Bitlocker stuff */ 2353 BlFveSecureBootCheckpointAppReturn(BootEntry, &ReturnArgs); 2354 #endif 2355 2356 /* Log in the boot status log the launch */ 2357 //BlBsdLogEntry(1, 0x12, &BootEntry->Guid, 0x14); 2358 2359 /* Unloac the boot application if we've returned */ 2360 BlImgUnloadBootApplication(AppHandle); 2361 2362 /* Keep going unless STATUS_RESTART_BOOT_APPLICATION */ 2363 } while (Status != 0xC0000453); 2364 2365 /* We've come back. Assume we need to launch the recovery sequence */ 2366 *Recover = TRUE; 2367 2368 /* Why did we get back? */ 2369 if (ReturnArgs.Flags & 1) 2370 { 2371 /* Flag 1 -- should we display advanced options? */ 2372 Status = BlGetBootOptionBoolean(BootEntry->BcdData, 2373 BcdLibraryBoolean_DisplayAdvancedOptions, 2374 &AdvancedOptions); 2375 if ((NT_SUCCESS(Status)) && (AdvancedOptions)) 2376 { 2377 /* Yes, so return with code 2 */ 2378 *LaunchCode = 2; 2379 } 2380 else 2381 { 2382 /* No, return with code 1 */ 2383 *LaunchCode = 1; 2384 } 2385 } 2386 else if (ReturnArgs.Flags & 4) 2387 { 2388 /* Flag 4 -- unknown */ 2389 *LaunchCode = 1; 2390 } 2391 else if (ReturnArgs.Flags & 8) 2392 { 2393 /* Flag 5 -- unknown */ 2394 *LaunchCode = 5; 2395 } 2396 else if (ReturnArgs.Flags & 0x10) 2397 { 2398 /* Flag 6 -- unknown */ 2399 *LaunchCode = 6; 2400 } 2401 else if (ReturnArgs.Flags & 0x20) 2402 { 2403 /* Flag 7 -- unknown */ 2404 *LaunchCode = 7; 2405 } 2406 else if (ReturnArgs.Flags & BL_RETURN_ARGUMENTS_NO_PAE_FLAG) 2407 { 2408 /* PAE is not supported -- refuse to boot */ 2409 *Recover = FALSE; 2410 BmFatalErrorEx(BL_FATAL_ERROR_NO_PAE, Status, 0, 0, 0); 2411 } 2412 2413 Quickie: 2414 /* All done, did we have an application path? */ 2415 if (AppPath) 2416 { 2417 /* Free it */ 2418 BlMmFreeHeap(AppPath); 2419 } 2420 2421 /* Back to the caller now */ 2422 return Status; 2423 } 2424 2425 NTSTATUS 2426 BmpLaunchBootEntry ( 2427 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 2428 _Out_ PULONG EntryIndex, 2429 _In_ ULONG LaunchCode, 2430 _In_ BOOLEAN LaunchWinRe 2431 ) 2432 { 2433 HANDLE BcdHandle; 2434 NTSTATUS Status; 2435 GUID ObjectId; 2436 BOOLEAN DoRecovery, AutoRecovery, DoSequence, RestartOnFailure; 2437 ULONG ErrorCode; 2438 BOOLEAN AdvancedOneTime, EditOneTime; 2439 2440 /* Check if this is the OS loader */ 2441 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD) 2442 { 2443 /* Check if one-time advanced options should be shown */ 2444 if (MiscGetBootOption(BootEntry->BcdData, 2445 BcdOSLoaderBoolean_AdvancedOptionsOneTime)) 2446 { 2447 /* Open the BCD */ 2448 BcdHandle = NULL; 2449 Status = BmOpenDataStore(BcdHandle); 2450 if (NT_SUCCESS(Status)) 2451 { 2452 /* Delete the option from the BCD, so it doesn't happen again */ 2453 ObjectId = BootEntry->Guid; 2454 BmPurgeOption(BcdHandle, 2455 &ObjectId, 2456 BcdOSLoaderBoolean_AdvancedOptionsOneTime); 2457 BmCloseDataStore(BcdHandle); 2458 } 2459 } 2460 2461 /* Check if one-time options editor should be shown */ 2462 if (MiscGetBootOption(BootEntry->BcdData, 2463 BcdOSLoaderBoolean_OptionsEditOneTime)) 2464 { 2465 /* Open the BCD */ 2466 BcdHandle = NULL; 2467 Status = BmOpenDataStore(BcdHandle); 2468 if (NT_SUCCESS(Status)) 2469 { 2470 /* Delete the option from the BCD, so it doesn't happen again */ 2471 ObjectId = BootEntry->Guid; 2472 BmPurgeOption(BcdHandle, 2473 &ObjectId, 2474 BcdOSLoaderBoolean_OptionsEditOneTime); 2475 BmCloseDataStore(BcdHandle); 2476 } 2477 } 2478 } 2479 2480 TryAgain: 2481 /* Disable recovery mode */ 2482 DoRecovery = FALSE; 2483 2484 /* Store globally which entry we are trying to boot */ 2485 BmpSelectedBootEntry = BootEntry; 2486 2487 /* Create any devices that aren't yet fully defined for this boot entry */ 2488 Status = BmpCreateDevices(BootEntry); 2489 if (!NT_SUCCESS(Status)) 2490 { 2491 /* That failed -- can we launch the recovery environment? */ 2492 if (!LaunchWinRe) 2493 { 2494 return Status; 2495 } 2496 2497 /* Yes, so return with the WinRe launch code */ 2498 LaunchCode = 2; 2499 goto Quickie; 2500 } 2501 2502 /* Is this an OS loader/ */ 2503 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD) 2504 { 2505 /* Is the one-time advanced options menu option present? */ 2506 Status = BlGetBootOptionBoolean(BootEntry->BcdData, 2507 BcdOSLoaderBoolean_AdvancedOptionsOneTime, 2508 &AdvancedOneTime); 2509 if (NT_SUCCESS(Status)) 2510 { 2511 /* Is it turned on? */ 2512 if (AdvancedOneTime) 2513 { 2514 /* Set the option this once */ 2515 BlAppendBootOptionBoolean(BootEntry, 2516 BcdLibraryBoolean_DisplayAdvancedOptions, 2517 TRUE); 2518 } 2519 else 2520 { 2521 /* It's not, so disable the option if active */ 2522 BlRemoveBootOption(BootEntry->BcdData, 2523 BcdLibraryBoolean_DisplayAdvancedOptions); 2524 } 2525 2526 /* Remove the one-time option. We've already purged it earlier */ 2527 BlRemoveBootOption(BootEntry->BcdData, 2528 BcdOSLoaderBoolean_AdvancedOptionsOneTime); 2529 } 2530 2531 /* Is the one-time options editor menu option present? */ 2532 Status = BlGetBootOptionBoolean(BootEntry->BcdData, 2533 BcdOSLoaderBoolean_OptionsEditOneTime, 2534 &EditOneTime); 2535 if (NT_SUCCESS(Status)) 2536 { 2537 /* Is it turned on? */ 2538 if (EditOneTime) 2539 { 2540 /* Set the option this once */ 2541 BlAppendBootOptionBoolean(BootEntry, 2542 BcdLibraryBoolean_DisplayOptionsEdit, 2543 TRUE); 2544 } 2545 else 2546 { 2547 /* It's not, so disable the option if active */ 2548 BlRemoveBootOption(BootEntry->BcdData, 2549 BcdLibraryBoolean_DisplayOptionsEdit); 2550 } 2551 2552 /* Remove the one-time option. We've already purged it earlier */ 2553 BlRemoveBootOption(BootEntry->BcdData, 2554 BcdOSLoaderBoolean_OptionsEditOneTime); 2555 } 2556 } 2557 2558 /* BCD handling done, transfer execution to this entry */ 2559 Status = BmpTransferExecution(BootEntry, &LaunchCode, &DoRecovery); 2560 if (!LaunchWinRe) 2561 { 2562 return Status; 2563 } 2564 2565 /* Check if boot was successful, or cancelled and we're not doing WinRE */ 2566 if (((NT_SUCCESS(Status)) || (Status == STATUS_CANCELLED)) && !(DoRecovery)) 2567 { 2568 return Status; 2569 } 2570 2571 /* Boot failed -- are we doing recovery? */ 2572 if (!DoRecovery) 2573 { 2574 /* Nope, bail out */ 2575 LaunchCode = 2; 2576 goto Quickie; 2577 } 2578 2579 Quickie: 2580 /* Get the recovery sequence */ 2581 if (MiscGetBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence)) 2582 { 2583 /* Check if the launch depends on auto-recovery being enabled or not */ 2584 if ((LaunchCode == 3) || (LaunchCode == 5) || (LaunchCode == 6)) 2585 { 2586 Status = BlGetBootOptionBoolean(BootEntry->BcdData, 2587 BcdLibraryBoolean_AutoRecoveryEnabled, 2588 &AutoRecovery); 2589 if (NT_SUCCESS(Status)) 2590 { 2591 /* Override the setting */ 2592 DoRecovery = AutoRecovery; 2593 } 2594 } 2595 } 2596 else 2597 { 2598 /* There's no recovery setting */ 2599 DoRecovery = FALSE; 2600 } 2601 2602 /* Check if we should restart on failure */ 2603 RestartOnFailure = FALSE; 2604 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 2605 BcdLibraryBoolean_RestartOnFailure, 2606 &RestartOnFailure); 2607 2608 /* Do the sequence if recovery is on, unless we should restart instead */ 2609 DoSequence = RestartOnFailure ? FALSE : DoRecovery; 2610 while (1) 2611 { 2612 /* Are we doing the recovery sequence? */ 2613 if (DoSequence) 2614 { 2615 /* Because of automatic recovery? */ 2616 if (AutoRecovery) 2617 { 2618 #if BL_BITLOCKER_SUPPORT 2619 /* Do bitlocker stuff */ 2620 BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, TRUE); 2621 #endif 2622 } 2623 2624 /* Launch the recovery sequence*/ 2625 Status = BmLaunchRecoverySequence(BootEntry, LaunchCode); 2626 2627 /* Was it launched automatically? */ 2628 if (AutoRecovery) 2629 { 2630 #if BL_BITLOCKER_SUPPORT 2631 /* Do bitlocker stuff */ 2632 BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, FALSE); 2633 #endif 2634 2635 /* No need to do this again */ 2636 AutoRecovery = FALSE; 2637 } 2638 2639 /* Did the recovery sequence work? */ 2640 if (NT_SUCCESS(Status)) 2641 { 2642 /* All good */ 2643 return STATUS_SUCCESS; 2644 } 2645 2646 /* Remove the sequence, don't do it again */ 2647 BlRemoveBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence); 2648 } 2649 2650 /* Recovery sequence also failed, show fatal error */ 2651 if (!BmpInternalBootError) 2652 { 2653 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0); 2654 } 2655 2656 /* Display the error menu */ 2657 ErrorCode = BmDisplayDumpError(BootEntry, LaunchCode); 2658 BmErrorPurge(); 2659 2660 /* See what the user wants to do */ 2661 switch (ErrorCode) 2662 { 2663 case TryAgain: 2664 /* Try again */ 2665 goto TryAgain; 2666 2667 case NextOs: 2668 /* Boot the next entry*/ 2669 break; 2670 2671 case OsSelection: 2672 /* Cancel the boot*/ 2673 return STATUS_CANCELLED; 2674 2675 case RecoverOem: 2676 /* Custom OEM recovery -- open the BCD */ 2677 Status = BmOpenDataStore(BcdHandle); 2678 if (NT_SUCCESS(Status)) 2679 { 2680 /* See what the custom sequence is */ 2681 Status = BmProcessCustomAction(BcdHandle, NULL); 2682 } 2683 2684 /* All done, close the BCD */ 2685 if (BcdHandle) 2686 { 2687 BmCloseDataStore(BcdHandle); 2688 } 2689 return Status; 2690 2691 case AdvancedOptions: 2692 /* Show the advanced options next iteration */ 2693 BlAppendBootOptionBoolean(BootEntry, 2694 BcdOSLoaderBoolean_AdvancedOptionsOneTime, 2695 TRUE); 2696 goto TryAgain; 2697 2698 case BootOptions: 2699 /* Show the options editor next iteration */ 2700 BlAppendBootOptionBoolean(BootEntry, 2701 BcdOSLoaderBoolean_OptionsEditOneTime, 2702 TRUE); 2703 goto TryAgain; 2704 2705 case Recover: 2706 /* Try the recovery sequence next time*/ 2707 DoSequence = TRUE; 2708 LaunchCode = 1; 2709 goto TryAgain; 2710 2711 default: 2712 /* Something unknown */ 2713 return STATUS_CANCELLED; 2714 } 2715 } 2716 2717 /* We are booting the next OS, so return success as to not kill the boot */ 2718 return STATUS_SUCCESS; 2719 } 2720 2721 /*++ 2722 * @name BmMain 2723 * 2724 * The BmMain function implements the Windows Boot Application entrypoint for 2725 * the Boot Manager. 2726 * 2727 * @param BootParameters 2728 * Pointer to the Boot Application Parameter Block. 2729 * 2730 * @return NT_SUCCESS if the image was loaded correctly, relevant error code 2731 * otherwise. 2732 * 2733 *--*/ 2734 NTSTATUS 2735 NTAPI 2736 BmMain ( 2737 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters 2738 ) 2739 { 2740 NTSTATUS Status, LibraryStatus; 2741 BL_LIBRARY_PARAMETERS LibraryParameters; 2742 PBL_RETURN_ARGUMENTS ReturnArguments; 2743 PGUID AppIdentifier; 2744 HANDLE BcdHandle, ResumeBcdHandle; 2745 PBL_BCD_OPTION EarlyOptions; 2746 PWCHAR Stylesheet; 2747 BOOLEAN XmlLoaded, DisableIntegrity, TestSigning, PersistBootSequence; 2748 BOOLEAN RebootOnError, CustomActions; 2749 ULONG SequenceId; 2750 PBL_LOADED_APPLICATION_ENTRY BootEntry; 2751 PGUID SequenceList; 2752 ULONG SequenceListCount; 2753 PBL_LOADED_APPLICATION_ENTRY* BootSequence; 2754 ULONG BootIndex; 2755 BOOLEAN ExitBootManager; 2756 BOOLEAN BootFailed; 2757 BOOLEAN BootOk; 2758 ULONG SequenceCount; 2759 BOOLEAN GetEntry; 2760 EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\r\n"); 2761 2762 /* Reading the BCD can change this later on */ 2763 RebootOnError = FALSE; 2764 2765 /* Save the start/end-of-POST time */ 2766 #if defined(_M_IX86) || defined(_M_X64) 2767 ApplicationStartTime = __rdtsc(); 2768 #else 2769 EfiPrintf(L"No time source defined for this platform\r\n"); 2770 ApplicationStartTime = 0; 2771 #endif 2772 PostTime = ApplicationStartTime; 2773 2774 /* Setup the boot library parameters for this application */ 2775 BlSetupDefaultParameters(&LibraryParameters); 2776 LibraryParameters.TranslationType = BlNone; 2777 LibraryParameters.LibraryFlags = 0x400 | 0x8; 2778 LibraryParameters.MinimumAllocationCount = 16; 2779 LibraryParameters.MinimumHeapSize = 512 * 1024; 2780 2781 /* Initialize the boot library */ 2782 Status = BlInitializeLibrary(BootParameters, &LibraryParameters); 2783 if (!NT_SUCCESS(Status)) 2784 { 2785 /* Check for failure due to invalid application entry */ 2786 if (Status != STATUS_INVALID_PARAMETER_9) 2787 { 2788 /* Specifically print out what happened */ 2789 EfiPrintf(L"BlInitializeLibrary failed 0x%x\r\n", Status); 2790 } 2791 2792 /* Go to exit path */ 2793 goto Quickie; 2794 } 2795 2796 /* Get the application identifier */ 2797 AppIdentifier = BlGetApplicationIdentifier(); 2798 if (!AppIdentifier) 2799 { 2800 /* None was given, so set our default one */ 2801 AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR; 2802 } 2803 2804 /* Save our identifier */ 2805 BmApplicationIdentifier = *AppIdentifier; 2806 2807 /* Initialize the file system to open a handle to our root boot directory */ 2808 BmFwInitializeBootDirectoryPath(); 2809 2810 /* Load and initialize the boot configuration database (BCD) */ 2811 Status = BmOpenDataStore(&BcdHandle); 2812 if (NT_SUCCESS(Status)) 2813 { 2814 /* Copy the boot options */ 2815 Status = BlCopyBootOptions(BlpApplicationEntry.BcdData, &EarlyOptions); 2816 if (NT_SUCCESS(Status)) 2817 { 2818 /* Update them */ 2819 Status = BmpUpdateApplicationOptions(BcdHandle); 2820 if (!NT_SUCCESS(Status)) 2821 { 2822 /* Log a fatal error */ 2823 BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE, 2824 (ULONG_PTR)L"\\BCD", 2825 Status, 2826 0, 2827 0); 2828 } 2829 } 2830 } 2831 2832 #ifdef _SECURE_BOOT 2833 /* Initialize the secure boot machine policy */ 2834 Status = BmSecureBootInitializeMachinePolicy(); 2835 if (!NT_SUCCESS(Status)) 2836 { 2837 BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT, Status, 0, 0, 0); 2838 } 2839 #endif 2840 2841 /* Copy the library parameters and add the re-initialization flag */ 2842 RtlCopyMemory(&LibraryParameters, 2843 &BlpLibraryParameters, 2844 sizeof(LibraryParameters)); 2845 LibraryParameters.LibraryFlags |= (BL_LIBRARY_FLAG_REINITIALIZE_ALL | 2846 BL_LIBRARY_FLAG_REINITIALIZE); 2847 2848 /* Now that we've parsed the BCD, re-initialize the library */ 2849 LibraryStatus = BlInitializeLibrary(BootParameters, &LibraryParameters); 2850 if (!NT_SUCCESS(LibraryStatus) && (NT_SUCCESS(Status))) 2851 { 2852 Status = LibraryStatus; 2853 } 2854 2855 /* Initialize firmware-specific memory regions */ 2856 BmFwMemoryInitialize(); 2857 2858 /* Initialize the boot status data log (BSD) */ 2859 BmpInitializeBootStatusDataLog(); 2860 2861 /* Find our XSL stylesheet */ 2862 Stylesheet = BlResourceFindHtml(); 2863 if (!Stylesheet) 2864 { 2865 /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */ 2866 Status = STATUS_NOT_FOUND; 2867 EfiPrintf(L"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND); 2868 goto Quickie; 2869 } 2870 2871 /* Initialize the XML Engine (as a side-effect, resets cursor) */ 2872 Status = BlXmiInitialize(Stylesheet); 2873 if (!NT_SUCCESS(Status)) 2874 { 2875 EfiPrintf(L"\r\nBlXmiInitialize failed 0x%x\r\n", Status); 2876 goto Failure; 2877 } 2878 XmlLoaded = TRUE; 2879 2880 /* Check if there's an active bitmap visible */ 2881 if (!BlDisplayValidOemBitmap()) 2882 { 2883 /* Nope, make the screen black using BGFX */ 2884 if (!NT_SUCCESS(BmpBgDisplayClearScreen(0xFF000000))) 2885 { 2886 /* BGFX isn't active, use standard display */ 2887 BlDisplayClearScreen(); 2888 } 2889 } 2890 2891 #ifdef _BIT_LOCKER_ 2892 /* Bitlocker will take over screen UI if enabled */ 2893 FveDisplayScreen = BmFveDisplayScreen; 2894 #endif 2895 2896 /* Check if any bypass options are enabled */ 2897 BlImgQueryCodeIntegrityBootOptions(&BlpApplicationEntry, 2898 &DisableIntegrity, 2899 &TestSigning); 2900 if (!DisableIntegrity) 2901 { 2902 /* Integrity checks are enabled, so validate our signature */ 2903 Status = BmFwVerifySelfIntegrity(); 2904 if (!NT_SUCCESS(Status)) 2905 { 2906 /* Signature invalid, fail boot */ 2907 goto Failure; 2908 } 2909 } 2910 2911 2912 /* TEST MODE */ 2913 EfiPrintf(L"Performing memory allocator tests...\r\n"); 2914 { 2915 NTSTATUS Status; 2916 PHYSICAL_ADDRESS PhysicalAddress, PhysicalAddress2; 2917 2918 /* Allocate 1 physical page */ 2919 PhysicalAddress.QuadPart = 0; 2920 Status = BlMmAllocatePhysicalPages(&PhysicalAddress, BlLoaderData, 1, 0, 1); 2921 if (Status != STATUS_SUCCESS) 2922 { 2923 EfiPrintf(L"FAIL: Allocation status: %lx at address: %llx\r\n", Status, PhysicalAddress.QuadPart); 2924 EfiStall(100000000); 2925 } 2926 2927 /* Write some data */ 2928 *(PULONG)((ULONG_PTR)PhysicalAddress.QuadPart) = 0x55555151; 2929 2930 /* Free it */ 2931 Status = BlMmFreePhysicalPages(PhysicalAddress); 2932 if (Status != STATUS_SUCCESS) 2933 { 2934 EfiPrintf(L"FAIL: Memory free status: %lx\r\n", Status); 2935 EfiStall(100000000); 2936 } 2937 2938 /* Allocate a page again */ 2939 PhysicalAddress2.QuadPart = 0; 2940 Status = BlMmAllocatePhysicalPages(&PhysicalAddress2, BlLoaderData, 1, 0, 1); 2941 if (Status != STATUS_SUCCESS) 2942 { 2943 EfiPrintf(L"FAIL: Allocation status: %lx at address: %llx\r\n", Status, PhysicalAddress2.QuadPart); 2944 EfiStall(100000000); 2945 } 2946 2947 /* It should've given us the same page, since we freed it */ 2948 if (PhysicalAddress.QuadPart != PhysicalAddress2.QuadPart) 2949 { 2950 EfiPrintf(L"FAIL: Non-matching addresses: %llx %llx\r\n", PhysicalAddress.QuadPart, PhysicalAddress2.QuadPart); 2951 EfiStall(100000000); 2952 } 2953 2954 /* The data should still be there, since zero-ing is not on for bootmgr */ 2955 if (*(PULONG)((ULONG_PTR)PhysicalAddress2.QuadPart) != 0x55555151) 2956 { 2957 EfiPrintf(L"FAIL: Non-matching data: %lx %lx\r\n", 0x55555151, *(PULONG)((ULONG_PTR)PhysicalAddress2.QuadPart)); 2958 EfiStall(100000000); 2959 } 2960 2961 /* And free the second page again */ 2962 Status = BlMmFreePhysicalPages(PhysicalAddress); 2963 if (Status != STATUS_SUCCESS) 2964 { 2965 EfiPrintf(L"FAIL: Memory free status: %lx\r\n", Status); 2966 EfiStall(100000000); 2967 } 2968 } 2969 2970 /* Write out the first XML tag */ 2971 BlXmiWrite(L"<bootmgr/>"); 2972 2973 /* Check for factory reset */ 2974 BlSecureBootCheckForFactoryReset(); 2975 2976 /* Load the revocation list */ 2977 Status = BmFwRegisterRevocationList(); 2978 if (!NT_SUCCESS(Status)) 2979 { 2980 goto Failure; 2981 } 2982 2983 /* Register our custom progress routine */ 2984 BlUtlRegisterProgressRoutine(); 2985 2986 /* Display state is not currently cached */ 2987 BmDisplayStateCached = FALSE; 2988 2989 /* Check if we need to resume from hibernate */ 2990 Status = BmResumeFromHibernate(&ResumeBcdHandle); 2991 if (!NT_SUCCESS(Status)) 2992 { 2993 goto Failure; 2994 } 2995 2996 #ifdef BL_NET_SUPPORT 2997 /* Register multicast printing routine */ 2998 BlUtlRegisterMulticastRoutine(); 2999 #endif 3000 3001 /* Check if restart on failure is enabled */ 3002 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 3003 BcdLibraryBoolean_RestartOnFailure, 3004 &RebootOnError); 3005 3006 /* Check if the boot sequence is persisted */ 3007 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 3008 BcdBootMgrBoolean_PersistBootSequence, 3009 &PersistBootSequence); 3010 if (!NT_SUCCESS(Status)) 3011 { 3012 /* It usually is */ 3013 PersistBootSequence = TRUE; 3014 } 3015 3016 /* Check if there's custom actions to take */ 3017 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, 3018 BcdBootMgrBoolean_ProcessCustomActionsFirst, 3019 &CustomActions); 3020 if ((NT_SUCCESS(Status)) && (CustomActions)) 3021 { 3022 /* We don't support this yet */ 3023 EfiPrintf(L"Not implemented\r\n"); 3024 Status = STATUS_NOT_IMPLEMENTED; 3025 goto Failure; 3026 } 3027 3028 //BlResourceFindMessage(BM_MSG_TEST); 3029 3030 /* At last, enter the boot selection stage */ 3031 SequenceId = 0; 3032 GetEntry = FALSE; 3033 BootFailed = FALSE; 3034 SequenceList = NULL; 3035 BootSequence = NULL; 3036 SequenceCount = 0; 3037 while (1) 3038 { 3039 /* We don't have a boot entry nor a sequence ID */ 3040 BootEntry = NULL; 3041 BootOk = FALSE; 3042 3043 /* Do we have a hardcoded boot sequence set? */ 3044 if (!(BootSequence) && !(GetEntry)) 3045 { 3046 /* Not yet, read the BCD to see if one is there */ 3047 Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData, 3048 BcdBootMgrObjectList_BootSequence, 3049 &SequenceList, 3050 &SequenceListCount); 3051 if (NT_SUCCESS(Status)) 3052 { 3053 /* A GUID list for the boot sequence is set. Extract it */ 3054 Status = BmGetBootSequence(BcdHandle, 3055 SequenceList, 3056 SequenceListCount, 3057 BL_APPLICATION_ENTRY_FIXED_SEQUENCE, 3058 &BootSequence, 3059 &SequenceCount); 3060 if (NT_SUCCESS(Status)) 3061 { 3062 /* Don't get stuck in a loop repeating this sequence */ 3063 BlRemoveBootOption(BlpApplicationEntry.BcdData, 3064 BcdBootMgrObjectList_BootSequence); 3065 3066 /* But do check if we should persist it */ 3067 if (PersistBootSequence) 3068 { 3069 /* Yes -- so go select an entry now */ 3070 GetEntry = TRUE; 3071 } 3072 else 3073 { 3074 /* We shouldn't, so wipe it from the BCD too */ 3075 Status = BmPurgeOption(BcdHandle, 3076 &BmApplicationIdentifier, 3077 BcdBootMgrObjectList_BootSequence); 3078 if (!NT_SUCCESS(Status)) 3079 { 3080 /* Well that failed */ 3081 goto LoopQuickie; 3082 } 3083 } 3084 } 3085 } 3086 else 3087 { 3088 /* No boot entry sequence for us */ 3089 BootSequence = NULL; 3090 } 3091 } 3092 3093 /* Do we have a sequence active, and are we still processing it? */ 3094 if ((BootSequence) && ((GetEntry) || (SequenceId < SequenceCount))) 3095 { 3096 /* Extract the next entry in the sequence */ 3097 BootEntry = BootSequence[SequenceId]; 3098 BootSequence[SequenceId] = NULL; 3099 3100 /* Move to the next entry for next time */ 3101 SequenceId++; 3102 3103 /* Unless there won't be a a next time? */ 3104 if (SequenceId == SequenceCount) 3105 { 3106 /* Clean up, it's the last entry */ 3107 BlMmFreeHeap(BootSequence); 3108 BootSequence = NULL; 3109 } 3110 } 3111 else 3112 { 3113 /* Get the selected boot entry from the user */ 3114 ExitBootManager = FALSE; 3115 Status = BmpGetSelectedBootEntry(BcdHandle, 3116 &BootEntry, 3117 &BootIndex, 3118 &ExitBootManager); 3119 if (!(NT_SUCCESS(Status)) || (ExitBootManager)) 3120 { 3121 /* Selection failed, or user wants to exit */ 3122 goto LoopQuickie; 3123 } 3124 } 3125 3126 /* Did we have a BCD open? */ 3127 if (BcdHandle) 3128 { 3129 /* Close it, we'll be opening a new one */ 3130 BmCloseDataStore(BcdHandle); 3131 BcdHandle = NULL; 3132 } 3133 3134 /* Launch the selected entry */ 3135 Status = BmpLaunchBootEntry(BootEntry, &BootIndex, 0, TRUE); 3136 if (NT_SUCCESS(Status)) 3137 { 3138 /* Boot worked, uncache display and process the bad memory list */ 3139 BmDisplayStateCached = FALSE; 3140 BmpProcessBadMemory(); 3141 } 3142 else 3143 { 3144 /* Boot failed -- was it user driven? */ 3145 if (Status != STATUS_CANCELLED) 3146 { 3147 /* Nope, remember that booting failed */ 3148 BootFailed = TRUE; 3149 goto LoopQuickie; 3150 } 3151 3152 /* Yes -- the display is still valid */ 3153 BmDisplayStateCached = TRUE; 3154 } 3155 3156 /* Reopen the BCD */ 3157 Status = BmOpenDataStore(&BcdHandle); 3158 if (!NT_SUCCESS(Status)) 3159 { 3160 break; 3161 } 3162 3163 /* Put the BCD options back into our entry */ 3164 BlReplaceBootOptions(&BlpApplicationEntry, EarlyOptions); 3165 3166 /* Update our options one more time */ 3167 Status = BmpUpdateApplicationOptions(BcdHandle); 3168 if (NT_SUCCESS(Status)) 3169 { 3170 /* Boot was 100% OK */ 3171 BootOk = TRUE; 3172 } 3173 3174 LoopQuickie: 3175 /* Did we have a boot entry? */ 3176 if (BootEntry) 3177 { 3178 /* We can destroy it now */ 3179 BlDestroyBootEntry(BootEntry); 3180 } 3181 3182 /* Is this the success path? */ 3183 if (NT_SUCCESS(Status)) 3184 { 3185 /* Did we actually boot something? */ 3186 if (!BootOk) 3187 { 3188 /* Bope, fail out */ 3189 break; 3190 } 3191 } 3192 3193 /* This is the failure path... should we reboot? */ 3194 if (RebootOnError) 3195 { 3196 break; 3197 } 3198 }; 3199 3200 Failure: 3201 if (!BootFailed) 3202 { 3203 /* Check if we got here due to an internal error */ 3204 if (BmpInternalBootError) 3205 { 3206 /* If XML is available, display the error */ 3207 if (XmlLoaded) 3208 { 3209 //BmDisplayDumpError(0, 0); 3210 //BmErrorPurge(); 3211 } 3212 3213 /* Don't do a fatal error -- return back to firmware */ 3214 goto Quickie; 3215 } 3216 } 3217 3218 /* Log a general fatal error once we're here */ 3219 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0); 3220 3221 Quickie: 3222 /* Check if we should reboot */ 3223 if ((RebootOnError) || 3224 (BlpApplicationEntry.Flags & BL_APPLICATION_ENTRY_REBOOT_ON_ERROR)) 3225 { 3226 /* Reboot the box */ 3227 BlFwReboot(); 3228 Status = STATUS_SUCCESS; 3229 } 3230 else 3231 { 3232 /* Return back to the caller with the error argument encoded */ 3233 ReturnArguments = (PVOID)((ULONG_PTR)BootParameters + BootParameters->ReturnArgumentsOffset); 3234 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION; 3235 ReturnArguments->Status = Status; 3236 3237 /* Tear down the boot library */ 3238 BlDestroyLibrary(); 3239 } 3240 3241 /* Return back status */ 3242 return Status; 3243 } 3244 3245