[BOOTMGR]: Support for launching a recovery sequence.
[reactos.git] / reactos / boot / environ / app / bootmgr / bootmgr.c
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 ULONG 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 = RtlULongAdd(i, 1, &AppPathLength);
261 if (NT_SUCCESS(Status))
262 {
263 /* Check if it's safe to multiply by two */
264 Status = RtlULongMult(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 outoing 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 0xC0210000:
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 ULONG BootDirLength, PathLength;
651
652 /* Compute the length of the directory, and add a NUL */
653 BootDirLength = wcslen(BootDirectory);
654 Status = RtlULongAdd(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 = RtlULongAdd(PathLength, BootDirLength, &PathLength);
663 if (!NT_SUCCESS(Status))
664 {
665 goto Quickie;
666 }
667
668 /* Convert to bytes */
669 Status = RtlULongLongToULong(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 ULONG 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 = RtlULongAdd(PathLength, 1, &PathLength);
799 if (!NT_SUCCESS(Status))
800 {
801 goto Quickie;
802 }
803
804 /* Convert to bytes */
805 Status = RtlULongLongToULong(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 = RtlULongAdd(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 "reserved" attribute */
1039 Status = MmPapAllocatePhysicalPagesInRange(&PhysicalAddress,
1040 BlApplicationReserved,
1041 1,
1042 BlMemoryReserved,
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 VOID
1087 BlImgQueryCodeIntegrityBootOptions (
1088 _In_ PBL_LOADED_APPLICATION_ENTRY ApplicationEntry,
1089 _Out_ PBOOLEAN IntegrityChecksDisabled,
1090 _Out_ PBOOLEAN TestSigningEnabled
1091 )
1092 {
1093
1094 NTSTATUS Status;
1095 BOOLEAN Value;
1096
1097 /* Check if /DISABLEINTEGRITYCHECKS is on */
1098 Status = BlGetBootOptionBoolean(ApplicationEntry->BcdData,
1099 BcdLibraryBoolean_DisableIntegrityChecks,
1100 &Value);
1101 *IntegrityChecksDisabled = NT_SUCCESS(Status) && (Value);
1102
1103 /* Check if /TESTSIGNING is on */
1104 Status = BlGetBootOptionBoolean(ApplicationEntry->BcdData,
1105 BcdLibraryBoolean_AllowPrereleaseSignatures,
1106 &Value);
1107 *TestSigningEnabled = NT_SUCCESS(Status) && (Value);
1108 }
1109
1110 NTSTATUS
1111 BmFwVerifySelfIntegrity (
1112 VOID
1113 )
1114 {
1115 /* Check if we're booted by UEFI off the DVD directlry */
1116 if ((BlpBootDevice->DeviceType == LocalDevice) &&
1117 (BlpBootDevice->Local.Type == CdRomDevice) &&
1118 (BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI))
1119 {
1120 /* Windows actually bypasses integrity checks in this case. Works for us */
1121 return STATUS_SUCCESS;
1122 }
1123
1124 /* Our binaries aren't signed, so always return failure */
1125 return 0xC0000428;
1126 }
1127
1128 NTSTATUS
1129 BmFwRegisterRevocationList (
1130 VOID
1131 )
1132 {
1133 NTSTATUS Status;
1134 BOOLEAN SecureBootEnabled;
1135
1136 /* Is SecureBoot enabled? */
1137 Status = BlSecureBootIsEnabled(&SecureBootEnabled);
1138 if ((NT_SUCCESS(Status)) && (SecureBootEnabled))
1139 {
1140 EfiPrintf(L"SB not implemented revok\r\n");
1141 return STATUS_NOT_IMPLEMENTED;
1142 }
1143 else
1144 {
1145 /* Nothing to do without SecureBoot */
1146 Status = STATUS_SUCCESS;
1147 }
1148
1149 /* Return revocation result back to caller */
1150 return Status;
1151 }
1152
1153 NTSTATUS
1154 BmResumeFromHibernate (
1155 _Out_ PHANDLE BcdResumeHandle
1156 )
1157 {
1158 NTSTATUS Status;
1159 BOOLEAN AttemptResume;
1160
1161 /* Should we attempt to resume from hibernation? */
1162 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
1163 BcdBootMgrBoolean_AttemptResume,
1164 &AttemptResume);
1165 if (!NT_SUCCESS(Status))
1166 {
1167 /* Nope. Is automatic restart on crash enabled? */
1168 AttemptResume = FALSE;
1169 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
1170 BcdOSLoaderBoolean_DisableCrashAutoReboot,
1171 &AttemptResume);
1172 AttemptResume = (NT_SUCCESS(Status) && (AttemptResume));
1173 }
1174
1175 /* Don't do anything if there's no need to resume anything */
1176 if (!AttemptResume)
1177 {
1178 return STATUS_SUCCESS;
1179 }
1180
1181 /* Not yet implemented */
1182 EfiPrintf(L"Resume not supported\r\n");
1183 return STATUS_NOT_IMPLEMENTED;
1184 }
1185
1186 NTSTATUS
1187 BmpProcessBadMemory (
1188 VOID
1189 )
1190 {
1191 BL_PD_DATA_BLOB BadMemoryData;
1192 NTSTATUS Status;
1193
1194 /* Try to get the memory data from the memtest application */
1195 BadMemoryData.BlobSize = 0;
1196 BadMemoryData.Data = NULL;
1197 BadMemoryData.DataSize = 0;
1198 Status = BlPdQueryData(&BadMemoryGuid, NULL, &BadMemoryData);
1199 if (Status != STATUS_BUFFER_TOO_SMALL)
1200 {
1201 /* No results, or some other error */
1202 return Status;
1203 }
1204
1205 /* Not yet implemented */
1206 EfiPrintf(L"Bad page list persistence not implemented\r\n");
1207 return STATUS_NOT_IMPLEMENTED;
1208 }
1209
1210 NTSTATUS
1211 BmPurgeOption (
1212 _In_ HANDLE BcdHandle,
1213 _In_ PGUID ObjectId,
1214 _In_ ULONG Type
1215 )
1216 {
1217 HANDLE ObjectHandle;
1218 NTSTATUS Status;
1219
1220 /* Open the object */
1221 Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
1222 if (NT_SUCCESS(Status))
1223 {
1224 /* Delete the element */
1225 BcdDeleteElement(ObjectHandle, Type);
1226
1227 /* Close the object and set success */
1228 BiCloseKey(ObjectHandle);
1229 Status = STATUS_SUCCESS;
1230 }
1231
1232 /* Return the result */
1233 return Status;
1234 }
1235
1236 NTSTATUS
1237 BmGetEntryDescription (
1238 _In_ HANDLE BcdHandle,
1239 _In_ PGUID ObjectId,
1240 _Out_ PBCD_OBJECT_DESCRIPTION Description
1241 )
1242 {
1243 NTSTATUS Status;
1244 HANDLE ObjectHandle;
1245
1246 /* Open the BCD object */
1247 Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
1248 if (NT_SUCCESS(Status))
1249 {
1250 /* Make sure the caller passed this argument in */
1251 if (!Description)
1252 {
1253 /* Fail otherwise */
1254 Status = STATUS_INVALID_PARAMETER;
1255 }
1256 else
1257 {
1258 /* Query the description from the BCD interface */
1259 Status = BiGetObjectDescription(ObjectHandle, Description);
1260 }
1261
1262 /* Close the object key */
1263 BiCloseKey(ObjectHandle);
1264 }
1265
1266 /* Return the result back */
1267 return Status;
1268 }
1269
1270 NTSTATUS
1271 BmpPopulateBootEntryList (
1272 _In_ HANDLE BcdHandle,
1273 _In_ PGUID SequenceList,
1274 _In_ ULONG Flags,
1275 _Out_ PBL_LOADED_APPLICATION_ENTRY* BootSequence,
1276 _Out_ PULONG SequenceCount
1277 )
1278 {
1279 NTSTATUS Status;
1280 ULONG BootIndex, i, OptionSize;
1281 PBL_LOADED_APPLICATION_ENTRY BootEntry;
1282 PBL_BCD_OPTION Options;
1283 BCD_OBJECT_DESCRIPTION Description;
1284 BcdObjectType ObjectType;
1285 BOOLEAN HavePath, IsWinPe, SoftReboot;
1286 PWCHAR LoaderPath;
1287
1288 /* Initialize locals */
1289 Options = NULL;
1290 BootIndex = 0;
1291 Status = STATUS_NOT_FOUND;
1292
1293 /* Loop through every element in the sequence */
1294 for (i = 0; i < *SequenceCount; i++)
1295 {
1296 /* Assume failure */
1297 BootEntry = NULL;
1298
1299 /* Get the options for the sequence element */
1300 Status = BmGetOptionList(BcdHandle, SequenceList, &Options);
1301 if (!NT_SUCCESS(Status))
1302 {
1303 EfiPrintf(L"option list failed: %lx\r\n", Status);
1304 goto LoopQuickie;
1305 }
1306
1307 /* Make sure there's at least a path and description */
1308 if (!(MiscGetBootOption(Options, BcdLibraryDevice_ApplicationDevice)) ||
1309 !(MiscGetBootOption(Options, BcdLibraryString_Description)))
1310 {
1311 Status = STATUS_UNSUCCESSFUL;
1312 EfiPrintf(L"missing list failed: %lx\r\n", Status);
1313 goto LoopQuickie;
1314 }
1315
1316 /* Get the size of the BCD options and allocate a large enough entry */
1317 OptionSize = BlGetBootOptionListSize(Options);
1318 BootEntry = BlMmAllocateHeap(sizeof(*BootEntry) + OptionSize);
1319 if (!BootEntry)
1320 {
1321 Status = STATUS_NO_MEMORY;
1322 goto Quickie;
1323 }
1324
1325 /* Save it as part of the sequence */
1326 BootSequence[BootIndex] = BootEntry;
1327
1328 /* Initialize it, and copy the BCD data */
1329 RtlZeroMemory(BootEntry, sizeof(*BootEntry));
1330 BootEntry->Guid = *SequenceList;
1331 BootEntry->BcdData = (PBL_BCD_OPTION)(BootEntry + 1);
1332 BootEntry->Flags = Flags;
1333 RtlCopyMemory(BootEntry->BcdData, Options, OptionSize);
1334
1335 /* Get the object descriptor to find out what kind of entry it is */
1336 Status = BmGetEntryDescription(BcdHandle,
1337 &BootEntry->Guid,
1338 &Description);
1339 if (!NT_SUCCESS(Status))
1340 {
1341 EfiPrintf(L"missing desc failed: %lx\r\n", Status);
1342 goto LoopQuickie;
1343 }
1344
1345 /* Check if a path was given or not */
1346 HavePath = MiscGetBootOption(Options, BcdLibraryString_ApplicationPath) ?
1347 TRUE : FALSE;
1348
1349 /* Now select based on what type of object this is -- must be an app */
1350 ObjectType.PackedValue = Description.Type;
1351 if (ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION)
1352 {
1353 /* Then select based on what kind of app it is */
1354 switch (ObjectType.Application.ApplicationCode)
1355 {
1356 /* Another boot manager */
1357 case BCD_APPLICATION_TYPE_BOOTMGR:
1358 BootEntry->Flags |= BCD_APPLICATION_TYPE_BOOTMGR;
1359 break;
1360
1361 /* An OS loader */
1362 case BCD_APPLICATION_TYPE_OSLOADER:
1363 BootEntry->Flags |= BL_APPLICATION_ENTRY_WINLOAD;
1364
1365 /* Do we have a path for it? */
1366 if (!HavePath)
1367 {
1368 /* We'll try to make one up. Is this WinPE? */
1369 IsWinPe = FALSE;
1370 Status = BlGetBootOptionBoolean(Options,
1371 BcdOSLoaderBoolean_WinPEMode,
1372 &IsWinPe);
1373 if (!(NT_SUCCESS(Status)) && (Status != STATUS_NOT_FOUND))
1374 {
1375 goto Quickie;
1376 }
1377
1378 /* Use the appropriate path for WinPE or local install */
1379 LoaderPath = IsWinPe ?
1380 L"\\Windows\\System32\\boot\\winload.efi" :
1381 L"\\Windows\\System32\\winload.efi";
1382
1383 /* Add the path to the boot entry */
1384 Status = BlAppendBootOptionString(BootEntry, LoaderPath);
1385 if (!NT_SUCCESS(Status))
1386 {
1387 goto Quickie;
1388 }
1389
1390 /* We have a path now */
1391 HavePath = TRUE;
1392 }
1393 break;
1394
1395 /* A hibernate-resume application */
1396 case BCD_APPLICATION_TYPE_RESUME:
1397 BootEntry->Flags |= BL_APPLICATION_ENTRY_WINRESUME;
1398 break;
1399
1400 /* An older OS NTLDR */
1401 case BCD_APPLICATION_TYPE_NTLDR:
1402 BootEntry->Flags |= BL_APPLICATION_ENTRY_NTLDR;
1403 break;
1404
1405 /* An older OS SETUPLDR */
1406 case BCD_APPLICATION_TYPE_SETUPLDR:
1407 BootEntry->Flags |= BL_APPLICATION_ENTRY_SETUPLDR;
1408 break;
1409
1410 /* A 3rd party/Win9x boot sector */
1411 case BCD_APPLICATION_TYPE_BOOTSECTOR:
1412 BootEntry->Flags |= BL_APPLICATION_ENTRY_BOOTSECTOR;
1413 break;
1414
1415 /* Something else entirely */
1416 default:
1417 break;
1418 }
1419 }
1420
1421 /* We better have a path by now */
1422 if (!HavePath)
1423 {
1424 Status = STATUS_UNSUCCESSFUL;
1425 goto LoopQuickie;
1426 }
1427
1428 /* Check if this is a real mode startup.com */
1429 if ((ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION) &&
1430 (ObjectType.Application.ImageCode = BCD_IMAGE_TYPE_REAL_MODE) &&
1431 (ObjectType.Application.ApplicationCode == BCD_APPLICATION_TYPE_STARTUPCOM))
1432 {
1433 /* Check if PXE soft reboot will occur */
1434 Status = BlGetBootOptionBoolean(Options,
1435 BcdStartupBoolean_PxeSoftReboot,
1436 &SoftReboot);
1437 if ((NT_SUCCESS(Status)) && (SoftReboot))
1438 {
1439 /* Then it's a valid startup.com entry */
1440 BootEntry->Flags |= BL_APPLICATION_ENTRY_STARTUP;
1441 }
1442 }
1443
1444 LoopQuickie:
1445 /* All done with this entry -- did we have BCD options? */
1446 if (Options)
1447 {
1448 /* Free them, they're part of the entry now */
1449 BlMmFreeHeap(Options);
1450 Options = NULL;
1451 }
1452
1453 /* Did we fail anywhere? */
1454 if (!NT_SUCCESS(Status))
1455 {
1456 /* Yep -- did we fail with an active boot entry? */
1457 if (BootEntry)
1458 {
1459 /* Destroy it */
1460 BlDestroyBootEntry(BootEntry);
1461 BootSequence[BootIndex] = NULL;
1462 }
1463 }
1464 else
1465 {
1466 /* It worked, so populate the next index now */
1467 BootIndex++;
1468 }
1469
1470 /* And move to the next GUID in the sequence list */
1471 SequenceList++;
1472 }
1473
1474 Quickie:
1475 /* All done now -- did we have any BCD options? */
1476 if (Options)
1477 {
1478 /* Free them */
1479 BlMmFreeHeap(Options);
1480 }
1481
1482 /* Return the status */
1483 return Status;
1484 }
1485
1486 NTSTATUS
1487 BmGetBootSequence (
1488 _In_ HANDLE BcdHandle,
1489 _In_ PGUID SequenceList,
1490 _In_ ULONG SequenceListCount,
1491 _In_ ULONG Flags,
1492 _Out_ PBL_LOADED_APPLICATION_ENTRY** BootSequence,
1493 _Out_ PULONG SequenceCount
1494 )
1495 {
1496 PBL_LOADED_APPLICATION_ENTRY* Sequence;
1497 ULONG Count;
1498 NTSTATUS Status;
1499
1500 /* Allocate the sequence list */
1501 Sequence = BlMmAllocateHeap(SequenceListCount * sizeof(*Sequence));
1502 if (!Sequence)
1503 {
1504 return STATUS_NO_MEMORY;
1505 }
1506
1507 /* Populate the sequence list */
1508 Status = BmpPopulateBootEntryList(BcdHandle,
1509 SequenceList,
1510 Flags,
1511 Sequence,
1512 &Count);
1513 if (!NT_SUCCESS(Status))
1514 {
1515 /* Free the list on failure */
1516 BlMmFreeHeap(Sequence);
1517 }
1518 else
1519 {
1520 /* Otherwise, set success and return the list and count */
1521 Status = STATUS_SUCCESS;
1522 *BootSequence = Sequence;
1523 *SequenceCount = Count;
1524 }
1525
1526 /* All done */
1527 return Status;
1528 }
1529
1530 NTSTATUS
1531 BmEnumerateBootEntries (
1532 _In_ HANDLE BcdHandle,
1533 _Out_ PBL_LOADED_APPLICATION_ENTRY **BootSequence,
1534 _Out_ PULONG SequenceCount
1535 )
1536 {
1537 NTSTATUS Status;
1538 ULONG BootIndex, BootIniCount, BootEntryCount, BcdCount;
1539 PBL_LOADED_APPLICATION_ENTRY* Sequence;
1540 PGUID DisplayOrder;
1541 GUID DefaultObject;
1542 BOOLEAN UseDisplayList;
1543
1544 /* Initialize locals */
1545 BootIndex = 0;
1546
1547 /* First try to get the display list, if any */
1548 UseDisplayList = TRUE;
1549 Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData,
1550 BcdBootMgrObjectList_DisplayOrder,
1551 &DisplayOrder,
1552 &BcdCount);
1553 if (!NT_SUCCESS(Status))
1554 {
1555 /* No list, get the default entry instead */
1556 Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData,
1557 BcdBootMgrObject_DefaultObject,
1558 &DefaultObject);
1559 if (NT_SUCCESS(Status))
1560 {
1561 /* Set the array to just our entry */
1562 UseDisplayList = FALSE;
1563 BcdCount = 1;
1564 DisplayOrder = &DefaultObject;
1565 }
1566 else
1567 {
1568 /* No default list either, return success but no entries */
1569 *BootSequence = NULL;
1570 *SequenceCount = 0;
1571 Status = STATUS_SUCCESS;
1572 DisplayOrder = NULL;
1573 goto Quickie;
1574 }
1575 }
1576
1577 /* Check if boot.ini was used */
1578 BootIniCount = 0;
1579 if (BmBootIniUsed)
1580 {
1581 /* Get the entries from it */
1582 EfiPrintf(L"Boot.ini not supported\r\n");
1583 BootIniCount = 0;//BmBootIniGetEntryCount();
1584 }
1585
1586 /* Allocate an array large enough for the combined boot entries */
1587 BootEntryCount = BootIniCount + BcdCount;
1588 Sequence = BlMmAllocateHeap(BootEntryCount * sizeof(*Sequence));
1589 if (!Sequence)
1590 {
1591 Status = STATUS_NO_MEMORY;
1592 goto Quickie;
1593 }
1594
1595 /* Zero it out */
1596 RtlZeroMemory(Sequence, BootEntryCount * sizeof(*Sequence));
1597
1598 /* Check if we had BCD entries */
1599 if (BcdCount)
1600 {
1601 /* Populate the list of bootable entries */
1602 Status = BmpPopulateBootEntryList(BcdHandle,
1603 DisplayOrder,
1604 BL_APPLICATION_ENTRY_DISPLAY_ORDER,
1605 Sequence,
1606 &BcdCount);
1607 if (!NT_SUCCESS(Status))
1608 {
1609 /* Bail out */
1610 goto Quickie;
1611 }
1612 }
1613
1614 /* Check if we had boot.ini entries */
1615 if (BootIniCount)
1616 {
1617 /* TODO */
1618 EfiPrintf(L"Boot.ini not supported\r\n");
1619 }
1620
1621 /* Return success and the sequence + count populated */
1622 Status = STATUS_SUCCESS;
1623 *BootSequence = Sequence;
1624 *SequenceCount = BootIniCount + BcdCount;
1625
1626 Quickie:
1627 /* Check if we had allocated a GUID list */
1628 if ((UseDisplayList) && (DisplayOrder))
1629 {
1630 /* Free it */
1631 BlMmFreeHeap(DisplayOrder);
1632 }
1633
1634 /* Check if this is the failure path */
1635 if (!(NT_SUCCESS(Status)) && (Sequence))
1636 {
1637 /* Loop the remaining boot entries */
1638 while (BootIndex < BootEntryCount)
1639 {
1640 /* Check if it had been allocated */
1641 if (Sequence[BootIndex])
1642 {
1643 /* Free it */
1644 BlMmFreeHeap(Sequence[BootIndex]);
1645 }
1646
1647 /* Next*/
1648 BootIndex++;
1649 }
1650
1651 /* Free the whole sequence now */
1652 BlMmFreeHeap(Sequence);
1653 }
1654
1655 /* All done, return the result */
1656 return Status;
1657 }
1658
1659 VOID
1660 BmpGetDefaultBootEntry (
1661 _In_ PBL_LOADED_APPLICATION_ENTRY* Sequence,
1662 _In_ ULONG Count,
1663 _Out_ PBL_LOADED_APPLICATION_ENTRY* DefaultEntry,
1664 _Out_ PULONG DefaultIndex
1665 )
1666 {
1667 GUID DefaultObject;
1668 NTSTATUS Status;
1669 ULONG BootIndex;
1670
1671 /* Assume no default */
1672 *DefaultEntry = *Sequence;
1673 *DefaultIndex = 0;
1674
1675 /* Nothing to do if there's just one entry */
1676 if (Count == 1)
1677 {
1678 return;
1679 }
1680
1681 /* Get the default object, bail out if there isn't one */
1682 Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData,
1683 BcdBootMgrObject_DefaultObject,
1684 &DefaultObject);
1685 if (!(NT_SUCCESS(Status)) || !(Count))
1686 {
1687 return;
1688 }
1689
1690 /* Scan the boot sequence */
1691 for (BootIndex = 0; BootIndex < Count; BootIndex++)
1692 {
1693 /* Find one that matches the default */
1694 if (RtlEqualMemory(&Sequence[BootIndex]->Guid,
1695 &DefaultObject,
1696 sizeof(GUID)))
1697 {
1698 /* Return it */
1699 *DefaultEntry = Sequence[BootIndex];
1700 *DefaultIndex = BootIndex;
1701 return;
1702 }
1703 }
1704 }
1705
1706 BL_MENU_POLICY
1707 BmGetBootMenuPolicy (
1708 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
1709 )
1710 {
1711 NTSTATUS Status;
1712 BOOLEAN EmsEnabled;
1713 ULONGLONG BootMenuPolicy;
1714 ULONG OptionId;
1715
1716 /* Check if EMS is enabled */
1717 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
1718 BcdOSLoaderBoolean_EmsEnabled,
1719 &EmsEnabled);
1720 if ((NT_SUCCESS(Status)) && (EmsEnabled))
1721 {
1722 /* No boot menu */
1723 return MenuPolicyLegacy;
1724 }
1725
1726 /* Check what entry we are looking at */
1727 if (!BootEntry)
1728 {
1729 /* No entry, pick the selected one */
1730 BootEntry = BmpSelectedBootEntry;
1731 }
1732
1733 /* Do we still not have an entry? */
1734 if (!BootEntry)
1735 {
1736 /* Show the menu */
1737 return MenuPolicyStandard;
1738 }
1739
1740 /* Check if this is an OS loader */
1741 BootMenuPolicy = 0;
1742 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
1743 {
1744 /* Use the correct option ID */
1745 OptionId = BcdOSLoaderInteger_BootMenuPolicy;
1746 }
1747 else
1748 {
1749 /* Check if this is an OS resumer */
1750 if (!(BootEntry->Flags & BL_APPLICATION_ENTRY_WINRESUME))
1751 {
1752 /* Nope, so no reason for a menu */
1753 return MenuPolicyLegacy;
1754 }
1755
1756 /* Use the correct opetion ID */
1757 OptionId = BcdResumeInteger_BootMenuPolicy;
1758 }
1759
1760 /* Check the option ID for the boot menu policy */
1761 Status = BlGetBootOptionInteger(BootEntry->BcdData,
1762 OptionId,
1763 &BootMenuPolicy);
1764 if (NT_SUCCESS(Status))
1765 {
1766 /* We have one, return it */
1767 return BootMenuPolicy;
1768 }
1769
1770 /* No policy, so assume no menu */
1771 return MenuPolicyLegacy;
1772 }
1773
1774 VOID
1775 BmDisplayGetBootMenuStatus (
1776 _Out_ PL_MENU_STATUS MenuStatus
1777 )
1778 {
1779 /* For now, don't support key input at all */
1780 MenuStatus->AsULong = 0;
1781 MenuStatus->OemKey = UNICODE_NULL;
1782 MenuStatus->BootIndex = -1;
1783 }
1784
1785 NTSTATUS
1786 BmProcessCustomAction (
1787 _In_ HANDLE BcdHandle,
1788 _In_ PWCHAR ActionKey
1789 )
1790 {
1791 EfiPrintf(L"Custom actions not yet handled\r\n");
1792 return STATUS_NOT_IMPLEMENTED;
1793 }
1794
1795 VOID
1796 BmpProcessBootEntry (
1797 _In_ HANDLE BcdHandle,
1798 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
1799 _Out_ PBOOLEAN ExitBootManager
1800 )
1801 {
1802 BL_MENU_STATUS MenuStatus;
1803
1804 /* Don't exit */
1805 *ExitBootManager = FALSE;
1806
1807 /* If the legacy menu must be shown, or if we have a boot entry */
1808 if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) || (BootEntry))
1809 {
1810 /* Check if any key has been presseed */
1811 BmDisplayGetBootMenuStatus(&MenuStatus);
1812 if (MenuStatus.AnyKey)
1813 {
1814 /* Was the exit key pressed? */
1815 if (MenuStatus.Exit)
1816 {
1817 /* Don't display a menu, and exit */
1818 *ExitBootManager = TRUE;
1819 BmpDisplayBootMenu = FALSE;
1820 }
1821 else if (MenuStatus.OemKey)
1822 {
1823 /* Process the OEM key action */
1824 BmProcessCustomAction(BcdHandle, &MenuStatus.KeyValue);
1825 }
1826 else
1827 {
1828 /* Process other keys */
1829 EfiPrintf(L"TODO\r\n");
1830 }
1831 }
1832 }
1833 }
1834
1835 NTSTATUS
1836 BmpGetSelectedBootEntry (
1837 _In_ HANDLE BcdHandle,
1838 _Out_ PBL_LOADED_APPLICATION_ENTRY* SelectedBootEntry,
1839 _Out_ PULONG EntryIndex,
1840 _Out_ PBOOLEAN ExitBootManager
1841 )
1842 {
1843 NTSTATUS Status;
1844 PBL_LOADED_APPLICATION_ENTRY* Sequence;
1845 PBL_LOADED_APPLICATION_ENTRY Entry, SelectedEntry;
1846 ULONG Count, BootIndex, SelectedIndex;
1847 // BOOLEAN FoundFailedEntry;
1848 ULONGLONG Timeout;
1849
1850 /* Initialize locals */
1851 BootIndex = 0;
1852 Count = 0;
1853 Sequence = NULL;
1854 SelectedEntry = NULL;
1855
1856 /* Enumerate all the boot entries */
1857 Status = BmEnumerateBootEntries(BcdHandle, &Sequence, &Count);
1858 if (!NT_SUCCESS(Status))
1859 {
1860 /* Bail out if we failed */
1861 goto Quickie;
1862 }
1863
1864 /* Check if there are no entries */
1865 if (!Count)
1866 {
1867 /* This is fatal -- kill the system */
1868 Status = STATUS_FILE_INVALID;
1869 BmFatalErrorEx(BL_FATAL_ERROR_BCD_ENTRIES, (ULONG_PTR)L"\\BCD", Status, 0, 0);
1870 goto Quickie;
1871 }
1872
1873 /* Check if we don't yet have an array of failed boot entries */
1874 if (!BmpFailedBootEntries)
1875 {
1876 /* Allocate it */
1877 BmpFailedBootEntries = BlMmAllocateHeap(Count);
1878 if (BmpFailedBootEntries)
1879 {
1880 /* Zero it out */
1881 RtlZeroMemory(BmpFailedBootEntries, Count);
1882 }
1883 }
1884
1885 /* Check if we have a hardcoded boot override */
1886 if (BmBootEntryOverridePresent)
1887 {
1888 EfiPrintf(L"Hard-coded boot override mode not supported\r\n");
1889 }
1890
1891 /* Log the OS count */
1892 //BlLogEtwWrite(BOOT_BOOTMGR_MULTI_OS_COUNT);
1893
1894 /* Check if the display is already active and cached */
1895 if (!BmDisplayStateCached)
1896 {
1897 /* Check if we should display a boot menu */
1898 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
1899 BcdBootMgrBoolean_DisplayBootMenu,
1900 &BmpDisplayBootMenu);
1901 if (!NT_SUCCESS(Status))
1902 {
1903 /* Assume not */
1904 BmpDisplayBootMenu = FALSE;
1905 }
1906 }
1907
1908 /* Check if there's only one entry to boot anyway */
1909 if (Count == 1)
1910 {
1911 /* Read it */
1912 SelectedEntry = *Sequence;
1913
1914 /* Process it */
1915 BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager);
1916
1917 /* Check if we're not displaying a boot menu */
1918 if (!BmpDisplayBootMenu)
1919 {
1920 /* Now we are */
1921 BmpDisplayBootMenu = TRUE;
1922
1923 /* Return the entry and its index back */
1924 *EntryIndex = 0;
1925 *SelectedBootEntry = SelectedEntry;
1926 Status = STATUS_SUCCESS;
1927 goto Quickie;
1928 }
1929 }
1930 else
1931 {
1932 /* Get the default boot entry */
1933 BmpGetDefaultBootEntry(Sequence, Count, &SelectedEntry, &SelectedIndex);
1934
1935 /* Check if we have a failed boot entry array allocated */
1936 //FoundFailedEntry = FALSE;
1937 if (BmpFailedBootEntries)
1938 {
1939 /* Check if the default entry failed to boot */
1940 if (BmpFailedBootEntries[SelectedIndex])
1941 {
1942 /* Loop through the current boot sequence */
1943 for (SelectedIndex = 0; SelectedIndex < Count; SelectedIndex++)
1944 {
1945 /* Check if there's no sequence for this index, or it failed */
1946 while (!(Sequence[SelectedIndex]) ||
1947 (BmpFailedBootEntries[SelectedIndex]))
1948 {
1949 /* Remember that this is a failed entry */
1950 SelectedEntry = Sequence[SelectedIndex];
1951 //FoundFailedEntry = TRUE;
1952 BmpDisplayBootMenu = FALSE;
1953 }
1954 }
1955 }
1956 }
1957
1958 /* Check if the entry is an OS loader */
1959 if (SelectedEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
1960 {
1961 // todo
1962 EfiPrintf(L"todo path\r\n");
1963 }
1964
1965 /* Check if there's no timeout */
1966 Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
1967 BcdBootMgrInteger_Timeout,
1968 &Timeout);
1969 if ((NT_SUCCESS(Status) && !(Timeout)))
1970 {
1971 /* There isn't, so just process the default entry right away */
1972 BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager);
1973
1974 /* Check if we're not displaying a boot menu */
1975 if (!BmpDisplayBootMenu)
1976 {
1977 /* Now we are */
1978 BmpDisplayBootMenu = TRUE;
1979
1980 /* Return the entry and its index back */
1981 *EntryIndex = 0;
1982 *SelectedBootEntry = SelectedEntry;
1983 Status = STATUS_SUCCESS;
1984 goto Quickie;
1985 }
1986
1987 /* Remove the timeout for this boot instance */
1988 BlRemoveBootOption(BlpApplicationEntry.BcdData,
1989 BcdBootMgrInteger_Timeout);
1990 }
1991 }
1992
1993 /* Here is where we display the menu and list of tools */
1994 EfiPrintf(L"Tool selection not yet implemented\r\n");
1995 EfiStall(10000000);
1996 *SelectedBootEntry = NULL;
1997
1998 Quickie:
1999 /* We are done -- did we have a sequence? */
2000 if (Sequence)
2001 {
2002 /* Do we have any boot entries we parsed? */
2003 while (BootIndex < Count)
2004 {
2005 /* Get the current boot entry */
2006 Entry = Sequence[BootIndex];
2007
2008 /* Did we fail, or is is not the selected one? */
2009 if ((Entry) && ((Entry != SelectedEntry) || !(NT_SUCCESS(Status))))
2010 {
2011 /* Destroy it, as it won't be needed */
2012 BlDestroyBootEntry(Entry);
2013 }
2014 else if (Entry == SelectedEntry)
2015 {
2016 /* It's the selected one, return its index */
2017 *EntryIndex = BootIndex;
2018 }
2019
2020 /* Move to the next entry */
2021 BootIndex++;
2022 }
2023
2024 /* Free the sequence of entries */
2025 BlMmFreeHeap(Sequence);
2026 }
2027
2028 /* Return the selection result */
2029 return Status;
2030 }
2031
2032 NTSTATUS
2033 BmpLaunchBootEntry (
2034 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2035 _Out_ PULONG EntryIndex,
2036 _In_ ULONG LaunchCode,
2037 _In_ BOOLEAN LaunchWinRe
2038 );
2039
2040 NTSTATUS
2041 BmLaunchRecoverySequence (
2042 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2043 _In_ ULONG LaunchCode
2044 )
2045 {
2046 NTSTATUS Status;
2047 PBL_LOADED_APPLICATION_ENTRY RecoveryEntry;
2048 HANDLE BcdHandle;
2049 PGUID RecoverySequence;
2050 ULONG Count, i, RecoveryIndex, SequenceCount;
2051 PBL_LOADED_APPLICATION_ENTRY* Sequence;
2052
2053 RecoveryIndex = 0;
2054 Sequence = NULL;
2055 RecoverySequence = NULL;
2056 Count = 0;
2057 BcdHandle = NULL;
2058
2059 Status = BmOpenDataStore(&BcdHandle);
2060 if (NT_SUCCESS(Status))
2061 {
2062 Status = BlGetBootOptionGuidList(BootEntry->BcdData,
2063 BcdLibraryObjectList_RecoverySequence,
2064 &RecoverySequence,
2065 &SequenceCount);
2066 if (NT_SUCCESS(Status))
2067 {
2068 Status = BmGetBootSequence(BcdHandle,
2069 RecoverySequence,
2070 SequenceCount,
2071 BL_APPLICATION_ENTRY_RECOVERY,
2072 &Sequence,
2073 &Count);
2074 if (NT_SUCCESS(Status))
2075 {
2076 if (BcdHandle)
2077 {
2078 BmCloseDataStore(BcdHandle);
2079 }
2080
2081 for (i = 0; i < Count; ++i)
2082 {
2083 if (LaunchCode == 2 || LaunchCode == 5)
2084 {
2085 BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
2086 BlAppendBootOptionInteger(Sequence[i],
2087 BcdLibraryInteger_DisplayMessageOverride,
2088 4);
2089 }
2090 else if (LaunchCode == 3)
2091 {
2092 BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
2093 BlAppendBootOptionInteger(Sequence[i],
2094 BcdLibraryInteger_DisplayMessageOverride,
2095 10);
2096 }
2097
2098 Status = BmpLaunchBootEntry(Sequence[i], NULL, LaunchCode, FALSE);
2099 if (!NT_SUCCESS(Status))
2100 {
2101 break;
2102 }
2103 }
2104 }
2105
2106 if (Sequence)
2107 {
2108 for (RecoveryIndex = 0; RecoveryIndex < Count; RecoveryIndex++)
2109 {
2110 RecoveryEntry = Sequence[RecoveryIndex];
2111 if (RecoveryEntry)
2112 {
2113 BlDestroyBootEntry(RecoveryEntry);
2114 }
2115 }
2116 BlMmFreeHeap(Sequence);
2117 }
2118 }
2119
2120 if (RecoverySequence)
2121 {
2122 BlMmFreeHeap(RecoverySequence);
2123 }
2124 }
2125
2126 return Status;
2127 }
2128
2129 ULONG
2130 BmDisplayDumpError (
2131 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2132 _In_ ULONG LaunchCode
2133 )
2134 {
2135 ULONG BootError;
2136 NTSTATUS Status;
2137 BOOLEAN Restart, NoError;
2138
2139 BootError = 1;
2140
2141 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
2142 BcdLibraryBoolean_RestartOnFailure,
2143 &Restart);
2144 if ((NT_SUCCESS(Status)) && (Restart))
2145 {
2146 return BootError;
2147 }
2148
2149 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
2150 BcdBootMgrBoolean_NoErrorDisplay,
2151 &NoError);
2152 if ((NT_SUCCESS(Status)) && (NoError))
2153 {
2154 return BootError;
2155 }
2156
2157 if (BmpInternalBootError)
2158 {
2159 return (ULONG)BmpInternalBootError; // ???
2160 }
2161
2162 EfiPrintf(L"Error menu not yet implemented\r\n");
2163 return BootError;
2164 }
2165
2166 NTSTATUS
2167 BmpCreateDevices (
2168 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
2169 )
2170 {
2171 ULONG NextOffset, DataOffset, ListOffset;
2172 PBL_BCD_OPTION Option, ListOption;
2173 BcdElementType ElementType;
2174 PBCD_DEVICE_OPTION BcdDevice;
2175
2176 NextOffset = 0;
2177 do
2178 {
2179 Option = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + NextOffset);
2180 NextOffset = Option->NextEntryOffset;
2181
2182 if (Option->Empty)
2183 {
2184 continue;
2185 }
2186
2187 ElementType.PackedValue = Option->Type;
2188 if (ElementType.Format != BCD_TYPE_DEVICE)
2189 {
2190 continue;
2191 }
2192
2193 DataOffset = Option->DataOffset;
2194
2195 BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)BootEntry->BcdData + DataOffset);
2196 if (!(BcdDevice->DeviceDescriptor.Flags & 1))
2197 {
2198 continue;
2199 }
2200
2201 ListOption = NULL;
2202 ListOffset = Option->ListOffset;
2203 if (Option->ListOffset)
2204 {
2205 ListOption = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + ListOffset);
2206 }
2207
2208 EfiPrintf(L"Unspecified devices not yet supported: %p\r\n", ListOption);
2209 return STATUS_NOT_SUPPORTED;
2210 } while (NextOffset != 0);
2211
2212 return STATUS_SUCCESS;
2213 }
2214
2215 /* MOVE TO IMAGe.C */
2216 NTSTATUS
2217 BlImgLoadBootApplication (
2218 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2219 _Out_ PHANDLE AppHandle
2220 )
2221 {
2222 EfiPrintf(L"Loading application %p\r\n", BootEntry);
2223
2224 return STATUS_NOT_IMPLEMENTED;
2225 }
2226
2227 NTSTATUS
2228 BlImgStartBootApplication (
2229 _In_ HANDLE AppHandle,
2230 _Inout_ PBL_RETURN_ARGUMENTS ReturnArguments
2231 )
2232 {
2233 EfiPrintf(L"Starting application %p\r\n", AppHandle);
2234
2235 return STATUS_NOT_IMPLEMENTED;
2236 }
2237
2238 NTSTATUS
2239 BlImgUnloadBootApplication (
2240 _In_ HANDLE AppHandle
2241 )
2242 {
2243 EfiPrintf(L"Unloading application %p\r\n", AppHandle);
2244
2245 return STATUS_NOT_IMPLEMENTED;
2246 }
2247
2248 NTSTATUS
2249 BmpTransferExecution (
2250 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2251 _Out_ PULONG LaunchCode,
2252 _Out_ PBOOLEAN Recover
2253 )
2254 {
2255 PWCHAR AppPath;
2256 NTSTATUS Status;
2257 PBL_DEVICE_DESCRIPTOR AppDevice;
2258 BL_RETURN_ARGUMENTS ReturnArgs;
2259 BOOLEAN AdvancedOptions;
2260 HANDLE AppHandle;
2261
2262 Status = BlGetBootOptionString(BootEntry->BcdData,
2263 BcdLibraryString_ApplicationPath,
2264 &AppPath);
2265 if (!NT_SUCCESS(Status))
2266 {
2267 AppPath = NULL;
2268 }
2269
2270 if (BootEntry->Flags & BL_APPLICATION_ENTRY_STARTUP)
2271 {
2272 #if BL_NET_SUPPORT
2273 Status = BlNetSoftReboot(BootEntry);
2274 #else
2275 EfiPrintf(L"Net boot not supported\r\n");
2276 Status = STATUS_NOT_SUPPORTED;
2277 #endif
2278 goto Quickie;
2279 }
2280
2281 do
2282 {
2283 Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
2284 if (Status == STATUS_NOT_FOUND)
2285 {
2286 Status = BlGetBootOptionDevice(BootEntry->BcdData,
2287 BcdLibraryDevice_ApplicationDevice,
2288 &AppDevice,
2289 NULL);
2290 if (NT_SUCCESS(Status))
2291 {
2292 Status = BlFwEnumerateDevice(AppDevice);
2293 }
2294
2295 if (!NT_SUCCESS(Status))
2296 {
2297 BmFatalErrorEx(2, (ULONG_PTR)AppPath, Status, 0, 0);
2298 goto Quickie;
2299 }
2300
2301 Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
2302 }
2303
2304 if (Status == STATUS_CANCELLED)
2305 {
2306 if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) ||
2307 !(MiscGetBootOption(BootEntry->BcdData,
2308 BcdLibraryObjectList_RecoverySequence)))
2309 {
2310 goto Quickie;
2311 }
2312
2313 *LaunchCode = 4;
2314 *Recover = TRUE;
2315 goto Quickie;
2316 }
2317
2318 if (Status == 0xC0210000)
2319 {
2320 *LaunchCode = 4;
2321 *Recover = TRUE;
2322 goto Quickie;
2323 }
2324
2325 if (!NT_SUCCESS(Status))
2326 {
2327 BmFatalErrorEx(2, (ULONG_PTR)AppPath, Status, 0, 0);
2328 goto Quickie;
2329 }
2330
2331 RtlZeroMemory(&ReturnArgs, sizeof(ReturnArgs));
2332 //BmpLogApplicationLaunchEvent(&BootEntry->Guid, AppPath);
2333
2334 Status = BlImgStartBootApplication(AppHandle, &ReturnArgs);
2335
2336 #if BL_BITLOCKER_SUPPORT
2337 BlFveSecureBootCheckpointAppReturn(BootEntry, &ReturnArgs);
2338 #endif
2339
2340 //BlBsdLogEntry(1, 0x12, &BootEntry->Guid, 0x14);
2341
2342 BlImgUnloadBootApplication(AppHandle);
2343
2344 } while (Status != 0xC0000453);
2345
2346 *Recover = TRUE;
2347 if (ReturnArgs.Flags & 1)
2348 {
2349 Status = BlGetBootOptionBoolean(BootEntry->BcdData,
2350 BcdLibraryBoolean_DisplayAdvancedOptions,
2351 &AdvancedOptions);
2352 if ((NT_SUCCESS(Status)) && (AdvancedOptions))
2353 {
2354 *LaunchCode = 2;
2355 }
2356 else
2357 {
2358 *LaunchCode = 1;
2359 }
2360 }
2361 else if (ReturnArgs.Flags & 4)
2362 {
2363 *LaunchCode = 1;
2364 }
2365 else if (ReturnArgs.Flags & 8)
2366 {
2367 *LaunchCode = 5;
2368 }
2369 else if (ReturnArgs.Flags & 0x10)
2370 {
2371 *LaunchCode = 6;
2372 }
2373 else if (ReturnArgs.Flags & 0x20)
2374 {
2375 *LaunchCode = 7;
2376 }
2377 else if (ReturnArgs.Flags & 0x40)
2378 {
2379 *Recover = FALSE;
2380 BmFatalErrorEx(11, Status, 0, 0, 0);
2381 }
2382
2383 Quickie:
2384 if (AppPath)
2385 {
2386 BlMmFreeHeap(AppPath);
2387 }
2388
2389 return Status;
2390 }
2391
2392 NTSTATUS
2393 BmpLaunchBootEntry (
2394 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
2395 _Out_ PULONG EntryIndex,
2396 _In_ ULONG LaunchCode,
2397 _In_ BOOLEAN LaunchWinRe
2398 )
2399 {
2400 HANDLE BcdHandle;
2401 NTSTATUS Status;
2402 GUID ObjectId;
2403 BOOLEAN DoRecovery, AutoRecovery, DoRestart, RestartOnFailure;
2404 ULONG ErrorCode;
2405 BOOLEAN AdvancedOneTime, EditOneTime, Recover;
2406
2407 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
2408 {
2409 if (MiscGetBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime))
2410 {
2411 BcdHandle = NULL;
2412 Status = BmOpenDataStore(BcdHandle);
2413 if (NT_SUCCESS(Status))
2414 {
2415 ObjectId = BootEntry->Guid;
2416 BmPurgeOption(BcdHandle, &ObjectId, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
2417 BmCloseDataStore(BcdHandle);
2418 }
2419 }
2420 if (MiscGetBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime))
2421 {
2422 BcdHandle = NULL;
2423 Status = BmOpenDataStore(BcdHandle);
2424 if (NT_SUCCESS(Status))
2425 {
2426 ObjectId = BootEntry->Guid;
2427 BmPurgeOption(BcdHandle, &ObjectId, BcdOSLoaderBoolean_OptionsEditOneTime);
2428 BmCloseDataStore(BcdHandle);
2429 }
2430 }
2431 }
2432
2433 TryAgain:
2434 DoRecovery = FALSE;
2435 Recover = FALSE;
2436 BmpSelectedBootEntry = BootEntry;
2437
2438 Status = BmpCreateDevices(BootEntry);
2439 if (!NT_SUCCESS(Status))
2440 {
2441 if (!LaunchWinRe)
2442 {
2443 return Status;
2444 }
2445
2446 LaunchCode = 2;
2447 goto Quickie;
2448 }
2449
2450 if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
2451 {
2452 Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime, &AdvancedOneTime);
2453 if (NT_SUCCESS(Status))
2454 {
2455 if (AdvancedOneTime)
2456 {
2457 BlAppendBootOptionBoolean(BootEntry, BcdLibraryBoolean_DisplayAdvancedOptions);
2458 }
2459 else
2460 {
2461 BlRemoveBootOption(BootEntry->BcdData, BcdLibraryBoolean_DisplayAdvancedOptions);
2462 }
2463
2464 BlRemoveBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
2465 }
2466
2467 Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime, &EditOneTime);
2468 if (NT_SUCCESS(Status))
2469 {
2470 if (AdvancedOneTime)
2471 {
2472 BlAppendBootOptionBoolean(BootEntry, BcdLibraryBoolean_DisplayOptionsEdit);
2473 }
2474 else
2475 {
2476 BlRemoveBootOption(BootEntry->BcdData, BcdLibraryBoolean_DisplayOptionsEdit);
2477 }
2478
2479 BlRemoveBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime);
2480 }
2481 }
2482
2483 Status = BmpTransferExecution(BootEntry, &LaunchCode, &Recover);
2484 if (!LaunchWinRe)
2485 {
2486 return Status;
2487 }
2488
2489 DoRecovery = Recover;
2490
2491 if (((NT_SUCCESS(Status)) || (Status == STATUS_CANCELLED)) && !(Recover))
2492 {
2493 return Status;
2494 }
2495
2496 if (!Recover)
2497 {
2498 LaunchCode = 2;
2499 goto Quickie;
2500 }
2501
2502 Quickie:
2503 if (MiscGetBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence))
2504 {
2505 if ((LaunchCode == 3) || (LaunchCode == 5) || (LaunchCode == 6))
2506 {
2507 Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdLibraryBoolean_AutoRecoveryEnabled, &AutoRecovery);
2508 if (NT_SUCCESS(Status))
2509 {
2510 DoRecovery = AutoRecovery;
2511 }
2512 }
2513 }
2514 else
2515 {
2516 DoRecovery = FALSE;
2517 }
2518
2519 RestartOnFailure = FALSE;
2520 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, BcdLibraryBoolean_RestartOnFailure, &RestartOnFailure);
2521 DoRestart = RestartOnFailure ? FALSE : DoRecovery;
2522 while (1)
2523 {
2524 if (DoRestart)
2525 {
2526 if (AutoRecovery)
2527 {
2528 //BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, TRUE);
2529 }
2530
2531 Status = BmLaunchRecoverySequence(BootEntry, LaunchCode);
2532
2533 if (AutoRecovery)
2534 {
2535 //BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, FALSE);
2536 AutoRecovery = FALSE;
2537 }
2538
2539 if (NT_SUCCESS(Status))
2540 {
2541 return STATUS_SUCCESS;
2542 }
2543
2544 BlRemoveBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence);
2545 }
2546
2547 if (!BmpInternalBootError)
2548 {
2549 BmFatalErrorEx(4, Status, 0, 0, 0);
2550 }
2551
2552 ErrorCode = BmDisplayDumpError(BootEntry, LaunchCode);
2553 BmErrorPurge();
2554
2555 switch (ErrorCode)
2556 {
2557 case 6:
2558 goto TryAgain;
2559 case 5:
2560 break;
2561 case 4:
2562 return STATUS_CANCELLED;
2563 case 3:
2564 Status = BmOpenDataStore(BcdHandle);
2565 if (NT_SUCCESS(Status))
2566 {
2567 Status = BmProcessCustomAction(BcdHandle, NULL);
2568 }
2569 if (BcdHandle)
2570 {
2571 BmCloseDataStore(BcdHandle);
2572 }
2573 return Status;
2574 case 7:
2575 BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
2576 goto TryAgain;
2577 case 8:
2578 BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_OptionsEditOneTime);
2579 goto TryAgain;
2580 case 2:
2581 DoRestart = TRUE;
2582 LaunchCode = 1;
2583 goto TryAgain;
2584 default:
2585 return STATUS_CANCELLED;
2586 }
2587 }
2588
2589
2590
2591 return STATUS_SUCCESS;
2592 }
2593
2594 /*++
2595 * @name BmMain
2596 *
2597 * The BmMain function implements the Windows Boot Application entrypoint for
2598 * the Boot Manager.
2599 *
2600 * @param BootParameters
2601 * Pointer to the Boot Application Parameter Block.
2602 *
2603 * @return NT_SUCCESS if the image was loaded correctly, relevant error code
2604 * otherwise.
2605 *
2606 *--*/
2607 NTSTATUS
2608 BmMain (
2609 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
2610 )
2611 {
2612 NTSTATUS Status, LibraryStatus;
2613 BL_LIBRARY_PARAMETERS LibraryParameters;
2614 PBL_RETURN_ARGUMENTS ReturnArguments;
2615 PGUID AppIdentifier;
2616 HANDLE BcdHandle, ResumeBcdHandle;
2617 PBL_BCD_OPTION EarlyOptions;
2618 PWCHAR Stylesheet;
2619 BOOLEAN XmlLoaded, DisableIntegrity, TestSigning, PersistBootSequence;
2620 BOOLEAN RebootOnError, CustomActions;
2621 ULONG SequenceId;
2622 PBL_LOADED_APPLICATION_ENTRY BootEntry;
2623 PGUID SequenceList;
2624 ULONG SequenceListCount;
2625 PBL_LOADED_APPLICATION_ENTRY* BootSequence;
2626 ULONG BootIndex;
2627 BOOLEAN ExitBootManager;
2628 BOOLEAN BootFailed;
2629 BOOLEAN BootOk;
2630 ULONG SequenceCount;
2631 BOOLEAN GetEntry;
2632 EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\r\n");
2633
2634 /* Reading the BCD can change this later on */
2635 RebootOnError = FALSE;
2636
2637 /* Save the start/end-of-POST time */
2638 ApplicationStartTime = __rdtsc();
2639 PostTime = ApplicationStartTime;
2640
2641 /* Setup the boot library parameters for this application */
2642 BlSetupDefaultParameters(&LibraryParameters);
2643 LibraryParameters.TranslationType = BlNone;
2644 LibraryParameters.LibraryFlags = 0x400 | 0x8;
2645 LibraryParameters.MinimumAllocationCount = 16;
2646 LibraryParameters.MinimumHeapSize = 512 * 1024;
2647
2648 /* Initialize the boot library */
2649 Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
2650 if (!NT_SUCCESS(Status))
2651 {
2652 /* Check for failure due to invalid application entry */
2653 if (Status != STATUS_INVALID_PARAMETER_9)
2654 {
2655 /* Specifically print out what happened */
2656 EfiPrintf(L"BlInitializeLibrary failed 0x%x\r\n", Status);
2657 }
2658
2659 /* Go to exit path */
2660 goto Quickie;
2661 }
2662
2663 /* Get the application identifier */
2664 AppIdentifier = BlGetApplicationIdentifier();
2665 if (!AppIdentifier)
2666 {
2667 /* None was given, so set our default one */
2668 AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR;
2669 }
2670
2671 /* Save our identifier */
2672 BmApplicationIdentifier = *AppIdentifier;
2673
2674 /* Initialize the file system to open a handle to our root boot directory */
2675 BmFwInitializeBootDirectoryPath();
2676
2677 /* Load and initialize the boot configuration database (BCD) */
2678 Status = BmOpenDataStore(&BcdHandle);
2679 if (NT_SUCCESS(Status))
2680 {
2681 /* Copy the boot options */
2682 Status = BlCopyBootOptions(BlpApplicationEntry.BcdData, &EarlyOptions);
2683 if (NT_SUCCESS(Status))
2684 {
2685 /* Update them */
2686 Status = BmpUpdateApplicationOptions(BcdHandle);
2687 if (!NT_SUCCESS(Status))
2688 {
2689 /* Log a fatal error */
2690 BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE,
2691 (ULONG_PTR)L"\\BCD",
2692 Status,
2693 0,
2694 0);
2695 }
2696 }
2697 }
2698
2699 #ifdef _SECURE_BOOT
2700 /* Initialize the secure boot machine policy */
2701 Status = BmSecureBootInitializeMachinePolicy();
2702 if (!NT_SUCCESS(Status))
2703 {
2704 BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT, Status, 0, 0, 0);
2705 }
2706 #endif
2707
2708 /* Copy the library parameters and add the re-initialization flag */
2709 RtlCopyMemory(&LibraryParameters,
2710 &BlpLibraryParameters,
2711 sizeof(LibraryParameters));
2712 LibraryParameters.LibraryFlags |= (BL_LIBRARY_FLAG_REINITIALIZE_ALL |
2713 BL_LIBRARY_FLAG_REINITIALIZE);
2714
2715 /* Now that we've parsed the BCD, re-initialize the library */
2716 LibraryStatus = BlInitializeLibrary(BootParameters, &LibraryParameters);
2717 if (!NT_SUCCESS(LibraryStatus) && (NT_SUCCESS(Status)))
2718 {
2719 Status = LibraryStatus;
2720 }
2721
2722 /* Initialize firmware-specific memory regions */
2723 BmFwMemoryInitialize();
2724
2725 /* Initialize the boot status data log (BSD) */
2726 BmpInitializeBootStatusDataLog();
2727
2728 /* Find our XSL stylesheet */
2729 Stylesheet = BlResourceFindHtml();
2730 if (!Stylesheet)
2731 {
2732 /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */
2733 Status = STATUS_NOT_FOUND;
2734 EfiPrintf(L"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND);
2735 goto Quickie;
2736 }
2737
2738 /* Initialize the XML Engine (as a side-effect, resets cursor) */
2739 Status = BlXmiInitialize(Stylesheet);
2740 if (!NT_SUCCESS(Status))
2741 {
2742 EfiPrintf(L"\r\nBlXmiInitialize failed 0x%x\r\n", Status);
2743 goto Failure;
2744 }
2745 XmlLoaded = TRUE;
2746
2747 /* Check if there's an active bitmap visible */
2748 if (!BlDisplayValidOemBitmap())
2749 {
2750 /* Nope, make the screen black using BGFX */
2751 if (!NT_SUCCESS(BmpBgDisplayClearScreen(0xFF000000)))
2752 {
2753 /* BGFX isn't active, use standard display */
2754 BlDisplayClearScreen();
2755 }
2756 }
2757
2758 #ifdef _BIT_LOCKER_
2759 /* Bitlocker will take over screen UI if enabled */
2760 FveDisplayScreen = BmFveDisplayScreen;
2761 #endif
2762
2763 /* Check if any bypass options are enabled */
2764 BlImgQueryCodeIntegrityBootOptions(&BlpApplicationEntry,
2765 &DisableIntegrity,
2766 &TestSigning);
2767 if (!DisableIntegrity)
2768 {
2769 /* Integrity checks are enabled, so validate our signature */
2770 Status = BmFwVerifySelfIntegrity();
2771 if (!NT_SUCCESS(Status))
2772 {
2773 /* Signature invalid, fail boot */
2774 goto Failure;
2775 }
2776 }
2777
2778 /* Write out the first XML tag */
2779 BlXmiWrite(L"<bootmgr/>");
2780
2781 /* Check for factory resset */
2782 BlSecureBootCheckForFactoryReset();
2783
2784 /* Load the revocation list */
2785 Status = BmFwRegisterRevocationList();
2786 if (!NT_SUCCESS(Status))
2787 {
2788 goto Failure;
2789 }
2790
2791 /* Register our custom progress routine */
2792 BlUtlRegisterProgressRoutine();
2793
2794 /* Display state is not currently cached */
2795 BmDisplayStateCached = FALSE;
2796
2797 /* Check if we need to resume from hibernate */
2798 Status = BmResumeFromHibernate(&ResumeBcdHandle);
2799 if (!NT_SUCCESS(Status))
2800 {
2801 goto Failure;
2802 }
2803
2804 #ifdef BL_NET_SUPPORT
2805 /* Register multicast printing routine */
2806 BlUtlRegisterMulticastRoutine();
2807 #endif
2808
2809 /* Check if restart on failure is enabled */
2810 BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
2811 BcdLibraryBoolean_RestartOnFailure,
2812 &RebootOnError);
2813
2814 /* Check if the boot sequence is persisted */
2815 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
2816 BcdBootMgrBoolean_PersistBootSequence,
2817 &PersistBootSequence);
2818 if (!NT_SUCCESS(Status))
2819 {
2820 /* It usually is */
2821 PersistBootSequence = TRUE;
2822 }
2823
2824 /* Check if there's custom actions to take */
2825 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
2826 BcdBootMgrBoolean_ProcessCustomActionsFirst,
2827 &CustomActions);
2828 if ((NT_SUCCESS(Status)) && (CustomActions))
2829 {
2830 /* We don't suppport this yet */
2831 EfiPrintf(L"Not implemented\r\n");
2832 Status = STATUS_NOT_IMPLEMENTED;
2833 goto Failure;
2834 }
2835
2836 /* At last, enter the boot selection stage */
2837 SequenceId = 0;
2838 GetEntry = FALSE;
2839 BootFailed = FALSE;
2840 SequenceList = NULL;
2841 BootSequence = NULL;
2842 SequenceCount = 0;
2843 while (1)
2844 {
2845 /* We don't have a boot entry nor a sequence ID */
2846 BootEntry = NULL;
2847 BootOk = FALSE;
2848
2849 /* Do we have a hardcoded boot sequence set? */
2850 if (!(BootSequence) && !(GetEntry))
2851 {
2852 /* Not yet, read the BCD to see if one is there */
2853 Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData,
2854 BcdBootMgrObjectList_BootSequence,
2855 &SequenceList,
2856 &SequenceListCount);
2857 if (NT_SUCCESS(Status))
2858 {
2859 /* A GUID list for the boot sequence is set. Extract it */
2860 Status = BmGetBootSequence(BcdHandle,
2861 SequenceList,
2862 SequenceListCount,
2863 BL_APPLICATION_ENTRY_FIXED_SEQUENCE,
2864 &BootSequence,
2865 &SequenceCount);
2866 if (NT_SUCCESS(Status))
2867 {
2868 /* Don't get stuck in a loop repeating this sequence */
2869 BlRemoveBootOption(BlpApplicationEntry.BcdData,
2870 BcdBootMgrObjectList_BootSequence);
2871
2872 /* But do check if we should persist it */
2873 if (PersistBootSequence)
2874 {
2875 /* Yes -- so go select an entry now */
2876 GetEntry = TRUE;
2877 }
2878 else
2879 {
2880 /* We shouldn't, so wipe it from the BCD too */
2881 Status = BmPurgeOption(BcdHandle,
2882 &BmApplicationIdentifier,
2883 BcdBootMgrObjectList_BootSequence);
2884 if (!NT_SUCCESS(Status))
2885 {
2886 /* Well that failed */
2887 goto LoopQuickie;
2888 }
2889 }
2890 }
2891 }
2892 else
2893 {
2894 /* No boot entry sequence for us */
2895 BootSequence = NULL;
2896 }
2897 }
2898
2899 /* Do we have a sequence active, and are we still processing it? */
2900 if ((BootSequence) && ((GetEntry) || (SequenceId < SequenceCount)))
2901 {
2902 /* Extract the next entry in the sequence */
2903 BootEntry = BootSequence[SequenceId];
2904 BootSequence[SequenceId] = NULL;
2905
2906 /* Move to the next entry for next time */
2907 SequenceId++;
2908
2909 /* Unless there won't be a a next time? */
2910 if (SequenceId == SequenceCount)
2911 {
2912 /* Clean up, it's the last entry */
2913 BlMmFreeHeap(BootSequence);
2914 BootSequence = NULL;
2915 }
2916 }
2917 else
2918 {
2919 /* Get the selected boot entry from the user */
2920 ExitBootManager = FALSE;
2921 Status = BmpGetSelectedBootEntry(BcdHandle,
2922 &BootEntry,
2923 &BootIndex,
2924 &ExitBootManager);
2925 if (!(NT_SUCCESS(Status)) || (ExitBootManager))
2926 {
2927 /* Selection failed, or user wants to exit */
2928 goto LoopQuickie;
2929 }
2930 }
2931
2932 /* Did we have a BCD open? */
2933 if (BcdHandle)
2934 {
2935 /* Close it, we'll be opening a new one */
2936 BmCloseDataStore(BcdHandle);
2937 BcdHandle = NULL;
2938 }
2939
2940 /* Launch the selected entry */
2941 Status = BmpLaunchBootEntry(BootEntry, &BootIndex, 0, TRUE);
2942 if (NT_SUCCESS(Status))
2943 {
2944 /* Boot worked, uncache display and process the bad memory list */
2945 BmDisplayStateCached = FALSE;
2946 BmpProcessBadMemory();
2947 }
2948 else
2949 {
2950 /* Boot failed -- was it user driven? */
2951 if (Status != STATUS_CANCELLED)
2952 {
2953 /* Nope, remember that booting failed */
2954 BootFailed = TRUE;
2955 goto LoopQuickie;
2956 }
2957
2958 /* Yes -- the display is still valid */
2959 BmDisplayStateCached = TRUE;
2960 }
2961
2962 /* Reopen the BCD */
2963 Status = BmOpenDataStore(&BcdHandle);
2964 if (!NT_SUCCESS(Status))
2965 {
2966 break;
2967 }
2968
2969 /* Put the BCD options back into our entry */
2970 BlReplaceBootOptions(&BlpApplicationEntry, EarlyOptions);
2971
2972 /* Update our options one more time */
2973 Status = BmpUpdateApplicationOptions(BcdHandle);
2974 if (NT_SUCCESS(Status))
2975 {
2976 /* Boot was 100% OK */
2977 BootOk = TRUE;
2978 }
2979
2980 LoopQuickie:
2981 /* Did we have a boot entry? */
2982 if (BootEntry)
2983 {
2984 /* We can destroy it now */
2985 BlDestroyBootEntry(BootEntry);
2986 }
2987
2988 /* Is this the success path? */
2989 if (NT_SUCCESS(Status))
2990 {
2991 /* Did we actually boot something? */
2992 if (!BootOk)
2993 {
2994 /* Bope, fail out */
2995 break;
2996 }
2997 }
2998
2999 /* This is the failure path... should we reboot? */
3000 if (RebootOnError)
3001 {
3002 break;
3003 }
3004 };
3005
3006 Failure:
3007 if (!BootFailed)
3008 {
3009 /* Check if we got here due to an internal error */
3010 if (BmpInternalBootError)
3011 {
3012 /* If XML is available, display the error */
3013 if (XmlLoaded)
3014 {
3015 //BmDisplayDumpError(0, 0);
3016 //BmErrorPurge();
3017 }
3018
3019 /* Don't do a fatal error -- return back to firmware */
3020 goto Quickie;
3021 }
3022 }
3023
3024 /* Log a general fatal error once we're here */
3025 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0);
3026
3027 Quickie:
3028 /* Check if we should reboot */
3029 if ((RebootOnError) ||
3030 (BlpApplicationEntry.Flags & BL_APPLICATION_ENTRY_REBOOT_ON_ERROR))
3031 {
3032 /* Reboot the box */
3033 BlFwReboot();
3034 Status = STATUS_SUCCESS;
3035 }
3036 else
3037 {
3038 /* Return back to the caller with the error argument encoded */
3039 ReturnArguments = (PVOID)((ULONG_PTR)BootParameters + BootParameters->ReturnArgumentsOffset);
3040 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
3041 ReturnArguments->Status = Status;
3042
3043 /* Tear down the boot library */
3044 BlDestroyLibrary();
3045 }
3046
3047 /* Return back status */
3048 return Status;
3049 }
3050