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
OslFatalErrorEx(_In_ ULONG ErrorCode,_In_ ULONG Parameter1,_In_ ULONG_PTR Parameter2,_In_ ULONG_PTR Parameter3)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
OslAbortBoot(_In_ NTSTATUS Status)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
OslBlStatusErrorHandler(_In_ ULONG ErrorCode,_In_ ULONG Parameter1,_In_ ULONG_PTR Parameter2,_In_ ULONG_PTR Parameter3,_In_ ULONG_PTR Parameter4)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
OslpSanitizeLoadOptionsString(_In_ PWCHAR OptionString,_In_ PWCHAR SanitizeString)179 OslpSanitizeLoadOptionsString (
180 _In_ PWCHAR OptionString,
181 _In_ PWCHAR SanitizeString
182 )
183 {
184 /* TODO */
185 return;
186 }
187
188 VOID
OslpSanitizeStringOptions(_In_ PBL_BCD_OPTION BcdOptions)189 OslpSanitizeStringOptions (
190 _In_ PBL_BCD_OPTION BcdOptions
191 )
192 {
193 /* TODO */
194 return;
195 }
196
197 NTSTATUS
OslpRemoveInternalApplicationOptions(VOID)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
OslpCheckForcedFailure(VOID)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
OslpInitializeBootStatusDataLog(VOID)274 OslpInitializeBootStatusDataLog (
275 VOID
276 )
277 {
278 /* TODO */
279 return;
280 }
281
282 NTSTATUS
OslpReadWriteBootStatusData(_In_ BOOLEAN WriteAccess)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
OslpGetSetBootStatusData(_In_ BOOLEAN Read,_In_ RTL_BSD_ITEM_TYPE DataClass,_Out_ PVOID Buffer,_Inout_ PULONG Size)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
OslSetBootStatusData(_In_ BOOLEAN LastBootGood,_In_ BOOLEAN LastBootShutdown,_In_ BOOLEAN LastBootCheckpoint,_In_ ULONG UpdateIncrement,_In_ ULONG BootAttemptCount)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
OslGetBootStatusData(_Out_ PBOOLEAN LastBootGood,_Out_ PBOOLEAN LastBootShutdown,_Out_ PBOOLEAN LastBootCheckpoint,_Out_ PULONG LastBootId,_Out_ PBOOLEAN BootGood,_Out_ PBOOLEAN BootShutdown)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
OslpAdvancedOptionsRequested(VOID)522 OslpAdvancedOptionsRequested (
523 VOID
524 )
525 {
526 /* TODO */
527 return FALSE;
528 }
529
530 NTSTATUS
OslPrepareTarget(_Out_ PULONG ReturnFlags,_Out_ PBOOLEAN Jump)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
OslFwpKernelSetupPhase1(_In_ PLOADER_PARAMETER_BLOCK LoaderBlock)861 OslFwpKernelSetupPhase1 (
862 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
863 )
864 {
865 return STATUS_NOT_IMPLEMENTED;
866 }
867
868 NTSTATUS
OslArchpKernelSetupPhase0(_In_ PLOADER_PARAMETER_BLOCK LoaderBlock)869 OslArchpKernelSetupPhase0 (
870 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
871 )
872 {
873 return STATUS_NOT_IMPLEMENTED;
874 }
875
876 VOID
ArchRestoreProcessorFeatures(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
OslArchKernelSetup(_In_ ULONG Phase,_In_ PLOADER_PARAMETER_BLOCK LoaderBlock)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
OslExecuteTransition(VOID)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
OslpMain(_Out_ PULONG ReturnFlags)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
OslMain(_In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters)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