xref: /reactos/boot/environ/app/rosload/rosload.c (revision 9592728f)
1 /*
2  * COPYRIGHT:       See COPYING.ARM in the top level directory
3  * PROJECT:         ReactOS UEFI OS Loader
4  * FILE:            boot/environ/app/rosload/rosload.c
5  * PURPOSE:         OS Loader Entrypoint
6  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "rosload.h"
12 
13 NTSTATUS
14 OslArchTransferToKernel (
15     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
16     _In_ PVOID KernelEntrypoint
17     );
18 
19 /* DATA VARIABLES ************************************************************/
20 
21 PLOADER_PARAMETER_BLOCK OslLoaderBlock;
22 PVOID OslEntryPoint;
23 PVOID UserSharedAddress;
24 ULONGLONG ArchXCr0BitsToClear;
25 ULONGLONG ArchCr4BitsToClear;
26 BOOLEAN BdDebugAfterExitBootServices;
27 KDESCRIPTOR OslKernelGdt;
28 KDESCRIPTOR OslKernelIdt;
29 
30 ULONG_PTR OslImcHiveHandle;
31 ULONG_PTR OslMachineHiveHandle;
32 ULONG_PTR OslElamHiveHandle;
33 ULONG_PTR OslSystemHiveHandle;
34 
35 PBL_DEVICE_DESCRIPTOR OslLoadDevice;
36 PCHAR OslLoadOptions;
37 PWCHAR OslSystemRoot;
38 
39 LIST_ENTRY OslFreeMemoryDesctiptorsList;
40 LIST_ENTRY OslFinalMemoryMap;
41 LIST_ENTRY OslCoreExtensionSubGroups[2];
42 LIST_ENTRY OslLoadedFirmwareDriverList;
43 
44 BL_BUFFER_DESCRIPTOR OslFinalMemoryMapDescriptorsBuffer;
45 
46 GUID OslApplicationIdentifier;
47 
48 ULONG OslResetBootStatus;
49 BOOLEAN OslImcProcessingValid;
50 ULONG OslFreeMemoryDesctiptorsListSize;
51 PVOID OslMemoryDescriptorBuffer;
52 
53 BcdObjectType BlpSbdiCurrentApplicationType;
54 
55 PRTL_BSD_DATA BsdBootStatusData;
56 
57 OSL_BSD_ITEM_TABLE_ENTRY OslpBootStatusFields[RtlBsdItemMax] =
58 {
59     {
60         FIELD_OFFSET(RTL_BSD_DATA, Version),
61         sizeof(&BsdBootStatusData->Version)
62     },  // RtlBsdItemVersionNumber
63     {
64         FIELD_OFFSET(RTL_BSD_DATA, ProductType),
65         sizeof(&BsdBootStatusData->ProductType)
66     },  // RtlBsdItemProductType
67     {
68         FIELD_OFFSET(RTL_BSD_DATA, AabEnabled),
69         sizeof(&BsdBootStatusData->AabEnabled)
70     },  // RtlBsdItemAabEnabled
71     {
72         FIELD_OFFSET(RTL_BSD_DATA, AabTimeout),
73         sizeof(&BsdBootStatusData->AabTimeout)
74     },  // RtlBsdItemAabTimeout
75     {
76         FIELD_OFFSET(RTL_BSD_DATA, LastBootSucceeded),
77         sizeof(&BsdBootStatusData->LastBootSucceeded)
78     },  // RtlBsdItemBootGood
79     {
80         FIELD_OFFSET(RTL_BSD_DATA, LastBootShutdown),
81         sizeof(&BsdBootStatusData->LastBootShutdown)
82     },  // RtlBsdItemBootShutdown
83     {
84         FIELD_OFFSET(RTL_BSD_DATA, SleepInProgress),
85         sizeof(&BsdBootStatusData->SleepInProgress)
86     },  // RtlBsdSleepInProgress
87     {
88         FIELD_OFFSET(RTL_BSD_DATA, PowerTransition),
89         sizeof(&BsdBootStatusData->PowerTransition)
90     },  // RtlBsdPowerTransition
91     {
92         FIELD_OFFSET(RTL_BSD_DATA, BootAttemptCount),
93         sizeof(&BsdBootStatusData->BootAttemptCount)
94     },  // RtlBsdItemBootAttemptCount
95     {
96         FIELD_OFFSET(RTL_BSD_DATA, LastBootCheckpoint),
97         sizeof(&BsdBootStatusData->LastBootCheckpoint)
98     },  // RtlBsdItemBootCheckpoint
99     {
100         FIELD_OFFSET(RTL_BSD_DATA, LastBootId),
101         sizeof(&BsdBootStatusData->LastBootId)
102     },  // RtlBsdItemBootId
103     {
104         FIELD_OFFSET(RTL_BSD_DATA, LastSuccessfulShutdownBootId),
105         sizeof(&BsdBootStatusData->LastSuccessfulShutdownBootId)
106     },  // RtlBsdItemShutdownBootId
107     {
108         FIELD_OFFSET(RTL_BSD_DATA, LastReportedAbnormalShutdownBootId),
109         sizeof(&BsdBootStatusData->LastReportedAbnormalShutdownBootId)
110     },  // RtlBsdItemReportedAbnormalShutdownBootId
111     {
112         FIELD_OFFSET(RTL_BSD_DATA, ErrorInfo),
113         sizeof(&BsdBootStatusData->ErrorInfo)
114     },  // RtlBsdItemErrorInfo
115     {
116         FIELD_OFFSET(RTL_BSD_DATA, PowerButtonPressInfo),
117         sizeof(&BsdBootStatusData->PowerButtonPressInfo)
118     },  // RtlBsdItemPowerButtonPressInfo
119     {
120         FIELD_OFFSET(RTL_BSD_DATA, Checksum),
121         sizeof(&BsdBootStatusData->Checksum)
122     },  // RtlBsdItemChecksum
123 };
124 
125 ULONG OslBootAttemptCount;
126 ULONG OslBootCountUpdateRequestForAbort;
127 ULONG OslBootAttemptMaximum;
128 
129 ULONG OslBootCountUpdateIncrement;
130 
131 BOOLEAN OslCurrentBootCheckpoint;
132 BOOLEAN OslCurrentBootSucceeded;
133 BOOLEAN OslCurrentBootShutdown;
134 
135 /* FUNCTIONS *****************************************************************/
136 
137 VOID
138 OslFatalErrorEx (
139     _In_ ULONG ErrorCode,
140     _In_ ULONG Parameter1,
141     _In_ ULONG_PTR Parameter2,
142     _In_ ULONG_PTR Parameter3
143     )
144 {
145     /* For now just do this */
146     BlStatusPrint(L"FATAL ERROR IN ROSLOAD: %lx\n", ErrorCode);
147 }
148 
149 VOID
150 OslAbortBoot (
151     _In_ NTSTATUS Status
152     )
153 {
154     /* For now just do this */
155     BlStatusPrint(L"BOOT ABORTED: %lx\n", Status);
156 }
157 
158 NTSTATUS
159 OslBlStatusErrorHandler (
160     _In_ ULONG ErrorCode,
161     _In_ ULONG Parameter1,
162     _In_ ULONG_PTR Parameter2,
163     _In_ ULONG_PTR Parameter3,
164     _In_ ULONG_PTR Parameter4
165     )
166 {
167     /* We only filter error code 4 */
168     if (ErrorCode != 4)
169     {
170         return STATUS_NOT_IMPLEMENTED;
171     }
172 
173     /* Handle error 4 as a fatal error 3 internally */
174     OslFatalErrorEx(3, Parameter1, Parameter2, Parameter3);
175     return STATUS_SUCCESS;
176 }
177 
178 VOID
179 OslpSanitizeLoadOptionsString (
180     _In_ PWCHAR OptionString,
181     _In_ PWCHAR SanitizeString
182     )
183 {
184     /* TODO */
185     return;
186 }
187 
188 VOID
189 OslpSanitizeStringOptions (
190     _In_ PBL_BCD_OPTION BcdOptions
191     )
192 {
193     /* TODO */
194     return;
195 }
196 
197 NTSTATUS
198 OslpRemoveInternalApplicationOptions (
199     VOID
200     )
201 {
202     PWCHAR LoadString;
203     NTSTATUS Status;
204 
205     /* Assume success */
206     Status = STATUS_SUCCESS;
207 
208     /* Remove attempts to disable integrity checks or ELAM driver load */
209     BlRemoveBootOption(BlpApplicationEntry.BcdData,
210                        BcdLibraryBoolean_DisableIntegrityChecks);
211     BlRemoveBootOption(BlpApplicationEntry.BcdData,
212                        BcdOSLoaderBoolean_DisableElamDrivers);
213 
214     /* Get the command-line parameters, if any */
215     Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
216                                    BcdLibraryString_LoadOptionsString,
217                                    &LoadString);
218     if (NT_SUCCESS(Status))
219     {
220         /* Conver to upper case */
221         _wcsupr(LoadString);
222 
223         /* Remove the existing one */
224         BlRemoveBootOption(BlpApplicationEntry.BcdData,
225                            BcdLibraryString_LoadOptionsString);
226 
227         /* Sanitize strings we don't want */
228         OslpSanitizeLoadOptionsString(LoadString, L"DISABLE_INTEGRITY_CHECKS");
229         OslpSanitizeLoadOptionsString(LoadString, L"NOINTEGRITYCHECKS");
230         OslpSanitizeLoadOptionsString(LoadString, L"DISABLEELAMDRIVERS");
231 
232         /* Add the sanitized one back */
233         Status = BlAppendBootOptionString(&BlpApplicationEntry,
234                                           BcdLibraryString_LoadOptionsString,
235                                           LoadString);
236 
237         /* Free the original BCD one */
238         BlMmFreeHeap(LoadString);
239     }
240 
241     /* One more pass for secure-boot options */
242     OslpSanitizeStringOptions(BlpApplicationEntry.BcdData);
243 
244     /* All good */
245     return Status;
246 }
247 
248 NTSTATUS
249 OslpCheckForcedFailure (
250     VOID
251     )
252 {
253     ULONG64 ForceReason;
254     NTSTATUS Status;
255 
256     /* Read the option */
257     Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
258                                     BcdOSLoaderInteger_ForceFailure,
259                                     &ForceReason);
260     if (NT_SUCCESS(Status) && (ForceReason < 4))
261     {
262         /* For reasons above 3, don't actually do anything */
263         if (ForceReason > 3)
264         {
265             return STATUS_SUCCESS;
266         }
267     }
268 
269     /* If the option isn't there or invalid, always return success */
270     return STATUS_SUCCESS;
271 }
272 
273 VOID
274 OslpInitializeBootStatusDataLog (
275     VOID
276     )
277 {
278     /* TODO */
279     return;
280 }
281 
282 NTSTATUS
283 OslpReadWriteBootStatusData (
284     _In_ BOOLEAN WriteAccess
285     )
286 {
287     /* Are you trying to write? */
288     if (WriteAccess)
289     {
290         /* Have we already read? */
291         if (!BsdBootStatusData)
292         {
293             /* No -- fail */
294             return STATUS_UNSUCCESSFUL;
295         }
296     }
297     else if (BsdBootStatusData)
298     {
299         /* No -- you're trying to read and we already have the data: no-op */
300         return STATUS_SUCCESS;
301     }
302 
303     /* TODO */
304     return STATUS_NOT_IMPLEMENTED;
305 }
306 
307 NTSTATUS
308 OslpGetSetBootStatusData (
309     _In_ BOOLEAN Read,
310     _In_ RTL_BSD_ITEM_TYPE DataClass,
311     _Out_ PVOID Buffer,
312     _Inout_ PULONG Size
313     )
314 {
315     NTSTATUS Status;
316     ULONG Length, Offset;
317 
318     /* No data has been read yet, fail */
319     if (!BsdBootStatusData)
320     {
321         return STATUS_UNSUCCESSFUL;
322     }
323 
324     /* Invalid data item, fail */
325     if (DataClass >= RtlBsdItemMax)
326     {
327         return STATUS_INVALID_PARAMETER;
328     }
329 
330     /* Capture the length and offset */
331     Length = OslpBootStatusFields[DataClass].Size;
332     Offset = OslpBootStatusFields[DataClass].Offset;
333 
334     /* Make sure it doesn't overflow past the structure we've read */
335     if ((Length + Offset) > BsdBootStatusData->Version)
336     {
337         return STATUS_REVISION_MISMATCH;
338     }
339 
340     /* Make sure we have enough space */
341     if (*Size >= Length)
342     {
343         /* We do -- is this a read? */
344         if (Read)
345         {
346             /* Yes, copy into the caller's buffer */
347             RtlCopyMemory(Buffer,
348                           (PVOID)((ULONG_PTR)BsdBootStatusData + Offset),
349                           Length);
350         }
351         else
352         {
353             /* It's a write, copy from caller's buffer */
354             RtlCopyMemory((PVOID)((ULONG_PTR)BsdBootStatusData + Offset),
355                           Buffer,
356                           Length);
357         }
358 
359         /* Set success */
360         Status = STATUS_SUCCESS;
361     }
362     else
363     {
364         /* Return size needed and failure code */
365         *Size = Length;
366         Status = STATUS_BUFFER_TOO_SMALL;
367     }
368 
369     /* All good */
370     return Status;
371 }
372 
373 NTSTATUS
374 OslSetBootStatusData (
375     _In_ BOOLEAN LastBootGood,
376     _In_ BOOLEAN LastBootShutdown,
377     _In_ BOOLEAN LastBootCheckpoint,
378     _In_ ULONG UpdateIncrement,
379     _In_ ULONG BootAttemptCount
380     )
381 {
382     NTSTATUS Status;
383     ULONG Size;
384 
385     /* Capture the BSD data in our globals, if needed */
386     Status = OslpReadWriteBootStatusData(FALSE);
387     if (!NT_SUCCESS(Status))
388     {
389         goto Quickie;
390     }
391 
392     /* Write last boot shutdown */
393     Size = sizeof(LastBootShutdown);
394     Status = OslpGetSetBootStatusData(FALSE,
395                                       RtlBsdItemBootShutdown,
396                                       &LastBootShutdown,
397                                       &Size);
398     if (!NT_SUCCESS(Status))
399     {
400         goto Quickie;
401     }
402 
403     /* Write last boot good */
404     Size = sizeof(LastBootGood);
405     Status = OslpGetSetBootStatusData(FALSE,
406                                       RtlBsdItemBootGood,
407                                       &LastBootGood,
408                                       &Size);
409     if (!NT_SUCCESS(Status))
410     {
411         goto Quickie;
412     }
413 
414     /* Write last boot checkpoint */
415     Size = sizeof(LastBootCheckpoint);
416     Status = OslpGetSetBootStatusData(FALSE,
417                                       RtlBsdItemBootCheckpoint,
418                                       &LastBootCheckpoint,
419                                       &Size);
420     if (!NT_SUCCESS(Status))
421     {
422         goto Quickie;
423     }
424 
425     /* Write boot attempt count */
426     Size = sizeof(BootAttemptCount);
427     Status = OslpGetSetBootStatusData(FALSE,
428                                       RtlBsdItemBootAttemptCount,
429                                       &BootAttemptCount,
430                                       &Size);
431     if (!NT_SUCCESS(Status))
432     {
433         goto Quickie;
434     }
435 
436     /* TODO: Update Boot ID*/
437 
438     /* Now write the data */
439     Status = OslpReadWriteBootStatusData(TRUE);
440 
441 Quickie:
442     return Status;
443 }
444 
445 NTSTATUS
446 OslGetBootStatusData (
447     _Out_ PBOOLEAN LastBootGood,
448     _Out_ PBOOLEAN LastBootShutdown,
449     _Out_ PBOOLEAN LastBootCheckpoint,
450     _Out_ PULONG LastBootId,
451     _Out_ PBOOLEAN BootGood,
452     _Out_ PBOOLEAN BootShutdown
453     )
454 {
455     NTSTATUS Status;
456     ULONG Size;
457     ULONG64 BootStatusPolicy;
458     BOOLEAN localBootShutdown, localBootGood;
459 
460     /* Capture the BSD data in our globals, if needed */
461     Status = OslpReadWriteBootStatusData(FALSE);
462     if (!NT_SUCCESS(Status))
463     {
464         goto Quickie;
465     }
466 
467     /* Read the last boot ID */
468     Size = sizeof(*LastBootId);
469     Status = OslpGetSetBootStatusData(TRUE, RtlBsdItemBootId, LastBootId, &Size);
470     if (!NT_SUCCESS(Status))
471     {
472         /* Set to zero if we couldn't find it */
473         *LastBootId = 0;
474     }
475 
476     /* Get the boot status policy */
477     Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
478                                     BcdOSLoaderInteger_BootStatusPolicy,
479                                     &BootStatusPolicy);
480     if (!NT_SUCCESS(Status))
481     {
482         /* Apply a default if none exists */
483         BootStatusPolicy = IgnoreShutdownFailures;
484     }
485 
486     /* Check if this was a good shutdown */
487     Size = sizeof(localBootShutdown);
488     Status = OslpGetSetBootStatusData(TRUE,
489                                       RtlBsdItemBootShutdown,
490                                       &localBootShutdown,
491                                       &Size);
492     if (!NT_SUCCESS(Status))
493     {
494         goto Quickie;
495     }
496 
497     /* Tell the caller */
498     *BootShutdown = localBootShutdown;
499 
500     /* Check if this was a good boot */
501     Size = sizeof(localBootGood);
502     Status = OslpGetSetBootStatusData(TRUE,
503                                       RtlBsdItemBootGood,
504                                       &localBootGood,
505                                       &Size);
506     if (!NT_SUCCESS(Status))
507     {
508         goto Quickie;
509     }
510 
511     /* Tell the caller*/
512     *BootGood = localBootGood;
513 
514     /* TODO: Additional logic for checkpoints and such */
515     Status = STATUS_NOT_IMPLEMENTED;
516 
517 Quickie:
518     return Status;
519 }
520 
521 BOOLEAN
522 OslpAdvancedOptionsRequested (
523     VOID
524     )
525 {
526     /* TODO */
527     return FALSE;
528 }
529 
530 NTSTATUS
531 OslPrepareTarget (
532     _Out_ PULONG ReturnFlags,
533     _Out_ PBOOLEAN Jump
534     )
535 {
536     PGUID AppId;
537     NTSTATUS Status;
538     PBL_DEVICE_DESCRIPTOR OsDevice;
539     PWCHAR SystemRoot;
540     SIZE_T RootLength, RootLengthWithSep;
541     ULONG i;
542     ULONG64 StartPerf, EndPerf;
543     RTL_BSD_DATA_POWER_TRANSITION PowerTransitionData;
544     PRTL_BSD_DATA_POWER_TRANSITION PowerBuffer;
545     ULONG OsDeviceHandle;
546     BOOLEAN LastBootGood, LastBootShutdown, LastBootCheckpoint;
547     ULONG BootId;
548     BOOLEAN BootGood, BootShutdown;
549     ULONG BsdSize;
550 
551     /* Initialize locals */
552     PowerBuffer = NULL;
553 
554     /* Assume no flags */
555     *ReturnFlags = 0;
556 
557     /* Make all registry handles invalid */
558     OslImcHiveHandle = -1;
559     OslMachineHiveHandle = -1;
560     OslElamHiveHandle = -1;
561     OslSystemHiveHandle = -1;
562 
563     /* Initialize memory lists */
564     InitializeListHead(&OslFreeMemoryDesctiptorsList);
565     InitializeListHead(&OslFinalMemoryMap);
566     InitializeListHead(&OslLoadedFirmwareDriverList);
567     for (i = 0; i < RTL_NUMBER_OF(OslCoreExtensionSubGroups); i++)
568     {
569         InitializeListHead(&OslCoreExtensionSubGroups[i]);
570     }
571 
572     /* Initialize the memory map descriptor buffer */
573     RtlZeroMemory(&OslFinalMemoryMapDescriptorsBuffer,
574                   sizeof(OslFinalMemoryMapDescriptorsBuffer));
575 
576     /* Initialize general pointers */
577     OslLoadDevice = NULL;
578     OslLoadOptions = NULL;
579     OslSystemRoot = NULL;
580     OslLoaderBlock = NULL;
581     OslMemoryDescriptorBuffer = NULL;
582 
583     /* Initialize general variables */
584     OslResetBootStatus = 0;
585     OslImcProcessingValid = FALSE;
586     OslFreeMemoryDesctiptorsListSize = 0;
587 
588     /* Capture the current TSC */
589     StartPerf = BlArchGetPerformanceCounter();
590 
591     /* Set our application type for SecureBoot/TPM purposes */
592     BlpSbdiCurrentApplicationType.Application.ObjectCode =
593         BCD_OBJECT_TYPE_APPLICATION;
594     BlpSbdiCurrentApplicationType.Application.ImageCode =
595         BCD_IMAGE_TYPE_BOOT_APP;
596     BlpSbdiCurrentApplicationType.Application.ApplicationCode =
597         BCD_APPLICATION_TYPE_OSLOADER;
598     BlpSbdiCurrentApplicationType.Application.Reserved = 0;
599 
600     /* Register an error handler */
601     BlpStatusErrorHandler = OslBlStatusErrorHandler;
602 
603     /* Get the application identifier and save it */
604     AppId = BlGetApplicationIdentifier();
605     if (AppId)
606     {
607         OslApplicationIdentifier = *AppId;
608     }
609 
610     /* Enable tracing */
611 #ifdef BL_ETW_SUPPORT
612     TraceLoggingRegister(&TlgOslBootProviderProv);
613 #endif
614 
615     /* Remove dangerous BCD options */
616     Status = OslpRemoveInternalApplicationOptions();
617     if (!NT_SUCCESS(Status))
618     {
619         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
620         goto Quickie;
621     }
622 
623     /* Get the OS device */
624     Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
625                                    BcdOSLoaderDevice_OSDevice,
626                                    &OsDevice,
627                                    0);
628     if (!NT_SUCCESS(Status))
629     {
630         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
631         goto Quickie;
632     }
633 
634     /* If the OS device is the boot device, use the one provided by bootlib */
635     if (OsDevice->DeviceType == BootDevice)
636     {
637         OsDevice = BlpBootDevice;
638     }
639 
640     /* Save it as a global for later */
641     OslLoadDevice = OsDevice;
642 
643     /* Get the system root */
644     Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
645                                    BcdOSLoaderString_SystemRoot,
646                                    &SystemRoot);
647     if (!NT_SUCCESS(Status))
648     {
649         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
650         goto Quickie;
651     }
652 
653     EfiPrintf(L"System root: %s\r\n", SystemRoot);
654 
655     /* Get the system root length and make sure it's slash-terminated */
656     RootLength = wcslen(SystemRoot);
657     if (SystemRoot[RootLength - 1] == OBJ_NAME_PATH_SEPARATOR)
658     {
659         /* Perfect, set it */
660         OslSystemRoot = SystemRoot;
661     }
662     else
663     {
664         /* Allocate a new buffer large enough to contain the slash */
665         RootLengthWithSep = RootLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
666         OslSystemRoot = BlMmAllocateHeap(RootLengthWithSep * sizeof(WCHAR));
667         if (!OslSystemRoot)
668         {
669             /* Bail out if we're out of memory */
670             Status = STATUS_NO_MEMORY;
671             EfiPrintf(L"Fail here: %d\r\n", __LINE__);
672             goto Quickie;
673         }
674 
675         /* Make a copy of the path, adding the separator */
676         wcscpy(OslSystemRoot, SystemRoot);
677         wcscat(OslSystemRoot, L"\\");
678 
679         /* Free the original one from the BCD library */
680         BlMmFreeHeap(SystemRoot);
681     }
682 
683     /* Initialize access to the BSD */
684     OslpInitializeBootStatusDataLog();
685 
686     /* Check if we're supposed to fail on purpose */
687     Status = OslpCheckForcedFailure();
688     if (!NT_SUCCESS(Status))
689     {
690         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
691         goto Quickie;
692     }
693 
694     /* Always disable VGA mode */
695     Status = BlAppendBootOptionBoolean(&BlpApplicationEntry,
696                                        BcdOSLoaderBoolean_DisableVgaMode,
697                                        TRUE);
698     if (!NT_SUCCESS(Status))
699     {
700         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
701         goto Quickie;
702     }
703 
704     /* Get telemetry data from the last boot */
705     Status = OslGetBootStatusData(&LastBootGood,
706                                   &LastBootShutdown,
707                                   &LastBootCheckpoint,
708                                   &BootId,
709                                   &BootGood,
710                                   &BootShutdown);
711     if (!NT_SUCCESS(Status))
712     {
713         /* Assume this is the very first boot and everything went well */
714         BootId = 0;
715         LastBootGood = TRUE;
716         LastBootShutdown = TRUE;
717         LastBootCheckpoint = TRUE;
718         BootGood = TRUE;
719         BootShutdown = TRUE;
720 
721         /* Set 0 boot attempts */
722         OslBootAttemptCount = 0;
723     }
724 
725     /* Set more attempt variables to their initial state */
726     OslResetBootStatus = TRUE;
727     OslBootCountUpdateRequestForAbort = 0;
728 
729     /* Read the current BSD data into the global buffer */
730     Status = OslpReadWriteBootStatusData(FALSE);
731     if (NT_SUCCESS(Status))
732     {
733         /* Get the power transition buffer from the BSD */
734         BsdSize = sizeof(PowerTransitionData);
735         Status = OslpGetSetBootStatusData(TRUE,
736                                           RtlBsdPowerTransition,
737                                           &PowerTransitionData,
738                                           &BsdSize);
739         if (NT_SUCCESS(Status))
740         {
741             /* Save the buffer */
742             PowerBuffer = &PowerTransitionData;
743         }
744     }
745 
746     /* Check if this is VHD boot, which gets 3 boot attempts instead of 2 */
747     OslBootAttemptMaximum = 2;
748     OslBootAttemptMaximum += BlDeviceIsVirtualPartitionDevice(OslLoadDevice, NULL);
749 
750     /* Check if the user wants to see the advanced menu */
751     if (!OslpAdvancedOptionsRequested())
752     {
753         /* The last boot failed more than the maximum */
754         if (!(LastBootGood) &&
755             (OslBootAttemptCount >= OslBootAttemptMaximum))
756         {
757             /* Return failure due to boot -- launch recovery */
758             *ReturnFlags |= 8;
759 
760             /* Update the attempt count and status variables */
761             OslBootAttemptCount = OslBootAttemptMaximum - 1;
762             OslCurrentBootCheckpoint = LastBootCheckpoint;
763             OslCurrentBootSucceeded = FALSE;
764             OslCurrentBootShutdown = LastBootShutdown;
765 
766             /* Crash with code 15 and abort boot */
767             OslFatalErrorEx(15, 0, 0, 0);
768             Status = STATUS_UNSUCCESSFUL;
769             EfiPrintf(L"Fail here: %d\r\n", __LINE__);
770             goto Quickie;
771         }
772 
773         /* We never made it far enough, more than the maximum */
774         if (!(LastBootCheckpoint) &&
775             (OslBootAttemptCount >= OslBootAttemptMaximum))
776         {
777             /* Return crash/dirty shutdown during boot attempt */
778             *ReturnFlags |= 0x10;
779 
780             /* Update the attempt count and status variables */
781             OslBootAttemptCount = OslBootAttemptMaximum - 1;
782             OslCurrentBootSucceeded = LastBootGood;
783             OslCurrentBootShutdown = LastBootShutdown;
784             OslCurrentBootCheckpoint = FALSE;
785 
786             /* Crash with code 16 and abort boot */
787             OslFatalErrorEx(16, 0, 0, 0);
788             Status = STATUS_UNSUCCESSFUL;
789             EfiPrintf(L"Fail here: %d\r\n", __LINE__);
790             goto Quickie;
791         }
792 
793         /* We failed to shutdown cleanly, and haven't booted yet */
794         if (!(LastBootShutdown) && !(OslBootAttemptCount))
795         {
796             /* Return crash/dirty shutdown */
797             *ReturnFlags |= 0x10;
798 
799             /* There's no boot attempt, so only update shutdown variables */
800             OslCurrentBootSucceeded = LastBootGood;
801             OslCurrentBootShutdown = TRUE;
802             OslCurrentBootCheckpoint = LastBootCheckpoint;
803 
804             /* Crash with code 16 and abort boot */
805             OslFatalErrorEx(16, 0, 0, 0);
806             Status = STATUS_UNSUCCESSFUL;
807             EfiPrintf(L"Fail here: %d\r\n", __LINE__);
808             goto Quickie;
809         }
810     }
811 
812     /* Officially increment the number of boot attempts */
813     OslBootAttemptCount++;
814 
815     /* No success yet, write to boot status file */
816     OslCurrentBootCheckpoint = FALSE;
817     OslCurrentBootSucceeded = FALSE;
818     OslCurrentBootShutdown = FALSE;
819     OslSetBootStatusData(FALSE,
820                          FALSE,
821                          FALSE,
822                          OslBootCountUpdateIncrement,
823                          OslBootAttemptCount);
824 
825     /* Open the OS Loader Device for Read/Write access */
826     Status = BlpDeviceOpen(OslLoadDevice,
827                            BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
828                            0,
829                            &OsDeviceHandle);
830     if (!NT_SUCCESS(Status))
831     {
832         EfiPrintf(L"Fail here: %d\r\n", __LINE__);
833         goto Quickie;
834     }
835 
836     /* That's all for now, folks */
837     Status = STATUS_NOT_IMPLEMENTED;
838     DBG_UNREFERENCED_LOCAL_VARIABLE(PowerBuffer);
839 
840     /* Printf perf */
841     EndPerf = BlArchGetPerformanceCounter();
842     EfiPrintf(L"Delta: %lld\r\n", EndPerf - StartPerf);
843 
844 Quickie:
845 #if BL_BITLOCKER_SUPPORT
846     /* Destroy the RNG/AES library for BitLocker */
847     SymCryptRngAesUninstantiate();
848 #endif
849 
850     /* Abort the boot */
851     OslAbortBoot(Status);
852 
853     /* This is a failure path, so never do the jump */
854     *Jump = FALSE;
855 
856     /* Return error code */
857     return Status;
858 }
859 
860 NTSTATUS
861 OslFwpKernelSetupPhase1 (
862     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
863     )
864 {
865     return STATUS_NOT_IMPLEMENTED;
866 }
867 
868 NTSTATUS
869 OslArchpKernelSetupPhase0 (
870     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
871     )
872 {
873     return STATUS_NOT_IMPLEMENTED;
874 }
875 
876 VOID
877 ArchRestoreProcessorFeatures (
878     VOID
879     )
880 {
881     /* Any XCR0 bits to clear? */
882     if (ArchXCr0BitsToClear)
883     {
884         /* Clear them */
885 #if defined(_MSC_VER) && !defined(__clang__) && !defined(_M_ARM)
886         __xsetbv(0, __xgetbv(0) & ~ArchXCr0BitsToClear);
887 #endif
888         ArchXCr0BitsToClear = 0;
889     }
890 
891     /* Any CR4 bits to clear? */
892     if (ArchCr4BitsToClear)
893     {
894         /* Clear them */
895 #if !defined(_M_ARM)
896         __writecr4(__readcr4() & ~ArchCr4BitsToClear);
897 #endif
898         ArchCr4BitsToClear = 0;
899     }
900 }
901 
902 NTSTATUS
903 OslArchKernelSetup (
904     _In_ ULONG Phase,
905     _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
906     )
907 {
908     /* For phase 0, do architectural setup */
909     if (Phase == 0)
910     {
911         return OslArchpKernelSetupPhase0(LoaderBlock);
912     }
913 
914     /* Nothing to do for Phase 1 */
915     if (Phase == 1)
916     {
917         return STATUS_SUCCESS;
918     }
919 
920     /* Relocate the self map */
921     BlMmRelocateSelfMap();
922 
923     /* Zero out the HAL Heap */
924     BlMmZeroVirtualAddressRange((PVOID)MM_HAL_VA_START,
925                                 MM_HAL_VA_END - MM_HAL_VA_START + 1);
926 
927     /* Move shared user data in its place */
928     BlMmMoveVirtualAddressRange((PVOID)KI_USER_SHARED_DATA,
929                                 UserSharedAddress,
930                                 PAGE_SIZE);
931 
932     /* Clear XCR0/CR4 CPU features that should be disabled before boot */
933     ArchRestoreProcessorFeatures();
934 
935     /* Good to go */
936     return STATUS_SUCCESS;
937 }
938 
939 NTSTATUS
940 OslExecuteTransition (
941     VOID
942     )
943 {
944     NTSTATUS Status;
945 
946     /* Is the debugger meant to be kept enabled throughout the boot phase? */
947     if (!BdDebugAfterExitBootServices)
948     {
949 #ifdef BL_KD_SUPPORT
950         /* No -- disable it */
951         BlBdStop();
952 #endif
953     }
954 
955     /* Setup Firmware for Phase 1 */
956     Status = OslFwpKernelSetupPhase1(OslLoaderBlock);
957     if (NT_SUCCESS(Status))
958     {
959         /* Setup kernel for Phase 2 */
960         Status = OslArchKernelSetup(2, OslLoaderBlock);
961         if (NT_SUCCESS(Status))
962         {
963 #ifdef BL_KD_SUPPORT
964             /* Stop the boot debugger */
965             BlBdStop();
966 #endif
967             /* Jump to the kernel entrypoint */
968             OslArchTransferToKernel(OslLoaderBlock, OslEntryPoint);
969 
970             /* Infinite loop if we got here */
971             for (;;);
972         }
973     }
974 
975     /* Return back with the failure code */
976     return Status;
977 }
978 
979 NTSTATUS
980 OslpMain (
981     _Out_ PULONG ReturnFlags
982     )
983 {
984     NTSTATUS Status;
985     BOOLEAN ExecuteJump;
986 #if !defined(_M_ARM)
987     CPU_INFO CpuInfo;
988     BOOLEAN NxEnabled;
989     LARGE_INTEGER MiscMsr;
990 
991     /* Check if the CPU supports NX */
992     BlArchCpuId(0x80000001, 0, &CpuInfo);
993     if (!(CpuInfo.Edx & 0x10000))
994     {
995         /* It doesn't, check if this is Intel */
996         EfiPrintf(L"NX disabled: %lx\r\n", CpuInfo.Edx);
997         if (BlArchGetCpuVendor() == CPU_INTEL)
998         {
999             /* Then turn off the MSR disable feature for it, enabling NX */
1000             MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
1001             EfiPrintf(L"NX being turned on: %llx\r\n", MiscMsr.QuadPart);
1002             MiscMsr.HighPart &= MSR_XD_ENABLE_MASK;
1003             MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
1004             __writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
1005             NxEnabled = TRUE;
1006         }
1007     }
1008 
1009     /* Turn on NX support with the CPU-generic MSR */
1010     __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_NXE);
1011 
1012 #endif
1013 
1014     /* Load the kernel */
1015     Status = OslPrepareTarget(ReturnFlags, &ExecuteJump);
1016     if (NT_SUCCESS(Status) && (ExecuteJump))
1017     {
1018         /* Jump to the kernel */
1019         Status = OslExecuteTransition();
1020     }
1021 
1022 #if !defined(_M_ARM)
1023     /* Retore NX support */
1024     __writemsr(MSR_EFER, __readmsr(MSR_EFER) ^ MSR_NXE);
1025 
1026     /* Did we manually enable NX? */
1027     if (NxEnabled)
1028     {
1029         /* Turn it back off */
1030         MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
1031         MiscMsr.HighPart |= ~MSR_XD_ENABLE_MASK;
1032         __writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
1033     }
1034 
1035 #endif
1036     /* Go back */
1037     return Status;
1038 }
1039 
1040 /*++
1041  * @name OslMain
1042  *
1043  *     The OslMain function implements the Windows Boot Application entrypoint for
1044  *     the OS Loader.
1045  *
1046  * @param  BootParameters
1047  *         Pointer to the Boot Application Parameter Block.
1048  *
1049  * @return NT_SUCCESS if the image was loaded correctly, relevant error code
1050  *         otherwise.
1051  *
1052  *--*/
1053 NTSTATUS
1054 NTAPI
1055 OslMain (
1056     _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
1057     )
1058 {
1059     BL_LIBRARY_PARAMETERS LibraryParameters;
1060     NTSTATUS Status;
1061     PBL_RETURN_ARGUMENTS ReturnArguments;
1062     PBL_APPLICATION_ENTRY AppEntry;
1063     CPU_INFO CpuInfo;
1064     ULONG Flags;
1065 
1066     /* Get the return arguments structure, and set our version */
1067     ReturnArguments = (PBL_RETURN_ARGUMENTS)((ULONG_PTR)BootParameters +
1068                                              BootParameters->ReturnArgumentsOffset);
1069     ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
1070 
1071     /* Get the application entry, and validate it */
1072     AppEntry = (PBL_APPLICATION_ENTRY)((ULONG_PTR)BootParameters +
1073                                        BootParameters->AppEntryOffset);
1074     if (!RtlEqualMemory(AppEntry->Signature,
1075                         BL_APP_ENTRY_SIGNATURE,
1076                         sizeof(AppEntry->Signature)))
1077     {
1078         /* Unrecognized, bail out */
1079         Status = STATUS_INVALID_PARAMETER_9;
1080         goto Quickie;
1081     }
1082 
1083 #if !defined(_M_ARM)
1084     /* Check if CPUID 01h is supported */
1085     if (BlArchIsCpuIdFunctionSupported(1))
1086     {
1087         /* Query CPU features */
1088         BlArchCpuId(1, 0, &CpuInfo);
1089 
1090         /* Check if PAE is supported */
1091         if (CpuInfo.Edx & 0x40)
1092         {
1093             EfiPrintf(L"PAE Supported, but won't be used\r\n");
1094         }
1095     }
1096 #endif
1097 
1098     /* Setup the boot library parameters for this application */
1099     BlSetupDefaultParameters(&LibraryParameters);
1100     LibraryParameters.TranslationType = BlVirtual;
1101     LibraryParameters.LibraryFlags = BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE |
1102                                      BL_LIBRARY_FLAG_REINITIALIZE_ALL;
1103     LibraryParameters.MinimumAllocationCount = 1024;
1104     LibraryParameters.MinimumHeapSize = 2 * 1024 * 1024;
1105     LibraryParameters.HeapAllocationAttributes = BlMemoryKernelRange;
1106     LibraryParameters.FontBaseDirectory = L"\\Reactos\\Boot\\Fonts";
1107     LibraryParameters.DescriptorCount = 512;
1108 
1109     /* Initialize the boot library */
1110     Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
1111     if (NT_SUCCESS(Status))
1112     {
1113         /* For testing, draw the logo */
1114         OslDrawLogo();
1115 
1116         /* Call the main routine */
1117         Status = OslpMain(&Flags);
1118 
1119         /* Return the flags, and destroy the boot library */
1120         ReturnArguments->Flags = Flags;
1121         BlDestroyLibrary();
1122     }
1123 
1124 Quickie:
1125     /* Return back to boot manager */
1126     ReturnArguments->Status = Status;
1127     return Status;
1128 }
1129 
1130