reactos/boot/environ/app/rosload/rosload.c
Alex Ionescu 9ec85c29e3 [ROSLOAD]: Continue work on target preparation OslPrepareTarget 2/104.
[ROSLOAD]: Stubplement OslpCheckForcedFailure, OslpGetSetBootStatusData, OslSetBootStatusData, OslGetBootStatusData.
[ROSLOAD]: Stub OslpInitializeBootStatusDataLog, OslpReadWriteBootStatusData.
[BOOTLIB]: Fix BlAppendBootOptionString to accept an actual BCD ID instead of hardcoding LibraryPath.
[BOOTLIB]: Fix BlAppendBootOptionBoolean to accept an actual BOOLEAN value instead of hardcoding TRUE.
[BOOTLIB]: Implement BlDeviceIsVirtualPartitionDevice.
[BOOTLIB]: Add missing BcdOSLoaderInteger_ForceFailure BCD value. Add BCDE_OSLOADER_TYPE_BOOT_STATUS_POLICY based on BcdEdit.exe and Geoff Chappel site.
2018-02-04 16:01:38 -08:00

1121 lines
31 KiB
C

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI OS Loader
* FILE: boot/environ/app/rosload/rosload.c
* PURPOSE: OS Loader Entrypoint
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "rosload.h"
NTSTATUS
OslArchTransferToKernel (
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock,
_In_ PVOID KernelEntrypoint
);
/* DATA VARIABLES ************************************************************/
PLOADER_PARAMETER_BLOCK OslLoaderBlock;
PVOID OslEntryPoint;
PVOID UserSharedAddress;
ULONGLONG ArchXCr0BitsToClear;
ULONGLONG ArchCr4BitsToClear;
BOOLEAN BdDebugAfterExitBootServices;
KDESCRIPTOR OslKernelGdt;
KDESCRIPTOR OslKernelIdt;
ULONG_PTR OslImcHiveHandle;
ULONG_PTR OslMachineHiveHandle;
ULONG_PTR OslElamHiveHandle;
ULONG_PTR OslSystemHiveHandle;
PBL_DEVICE_DESCRIPTOR OslLoadDevice;
PCHAR OslLoadOptions;
PWCHAR OslSystemRoot;
LIST_ENTRY OslFreeMemoryDesctiptorsList;
LIST_ENTRY OslFinalMemoryMap;
LIST_ENTRY OslCoreExtensionSubGroups[2];
LIST_ENTRY OslLoadedFirmwareDriverList;
BL_BUFFER_DESCRIPTOR OslFinalMemoryMapDescriptorsBuffer;
GUID OslApplicationIdentifier;
ULONG OslResetBootStatus;
BOOLEAN OslImcProcessingValid;
ULONG OslFreeMemoryDesctiptorsListSize;
PVOID OslMemoryDescriptorBuffer;
BcdObjectType BlpSbdiCurrentApplicationType;
PRTL_BSD_DATA BsdBootStatusData;
OSL_BSD_ITEM_TABLE_ENTRY OslpBootStatusFields[RtlBsdItemMax] =
{
{
FIELD_OFFSET(RTL_BSD_DATA, Version),
sizeof(&BsdBootStatusData->Version)
}, // RtlBsdItemVersionNumber
{
FIELD_OFFSET(RTL_BSD_DATA, ProductType),
sizeof(&BsdBootStatusData->ProductType)
}, // RtlBsdItemProductType
{
FIELD_OFFSET(RTL_BSD_DATA, AabEnabled),
sizeof(&BsdBootStatusData->AabEnabled)
}, // RtlBsdItemAabEnabled
{
FIELD_OFFSET(RTL_BSD_DATA, AabTimeout),
sizeof(&BsdBootStatusData->AabTimeout)
}, // RtlBsdItemAabTimeout
{
FIELD_OFFSET(RTL_BSD_DATA, LastBootSucceeded),
sizeof(&BsdBootStatusData->LastBootSucceeded)
}, // RtlBsdItemBootGood
{
FIELD_OFFSET(RTL_BSD_DATA, LastBootShutdown),
sizeof(&BsdBootStatusData->LastBootShutdown)
}, // RtlBsdItemBootShutdown
{
FIELD_OFFSET(RTL_BSD_DATA, SleepInProgress),
sizeof(&BsdBootStatusData->SleepInProgress)
}, // RtlBsdSleepInProgress
{
FIELD_OFFSET(RTL_BSD_DATA, PowerTransition),
sizeof(&BsdBootStatusData->PowerTransition)
}, // RtlBsdPowerTransition
{
FIELD_OFFSET(RTL_BSD_DATA, BootAttemptCount),
sizeof(&BsdBootStatusData->BootAttemptCount)
}, // RtlBsdItemBootAttemptCount
{
FIELD_OFFSET(RTL_BSD_DATA, LastBootCheckpoint),
sizeof(&BsdBootStatusData->LastBootCheckpoint)
}, // RtlBsdItemBootCheckpoint
{
FIELD_OFFSET(RTL_BSD_DATA, LastBootId),
sizeof(&BsdBootStatusData->LastBootId)
}, // RtlBsdItemBootId
{
FIELD_OFFSET(RTL_BSD_DATA, LastSuccessfulShutdownBootId),
sizeof(&BsdBootStatusData->LastSuccessfulShutdownBootId)
}, // RtlBsdItemShutdownBootId
{
FIELD_OFFSET(RTL_BSD_DATA, LastReportedAbnormalShutdownBootId),
sizeof(&BsdBootStatusData->LastReportedAbnormalShutdownBootId)
}, // RtlBsdItemReportedAbnormalShutdownBootId
{
FIELD_OFFSET(RTL_BSD_DATA, ErrorInfo),
sizeof(&BsdBootStatusData->ErrorInfo)
}, // RtlBsdItemErrorInfo
{
FIELD_OFFSET(RTL_BSD_DATA, PowerButtonPressInfo),
sizeof(&BsdBootStatusData->PowerButtonPressInfo)
}, // RtlBsdItemPowerButtonPressInfo
{
FIELD_OFFSET(RTL_BSD_DATA, Checksum),
sizeof(&BsdBootStatusData->Checksum)
}, // RtlBsdItemChecksum
};
ULONG OslBootAttemptCount;
ULONG OslBootCountUpdateRequestForAbort;
ULONG OslBootAttemptMaximum;
ULONG OslBootCountUpdateIncrement;
BOOLEAN OslCurrentBootCheckpoint;
BOOLEAN OslCurrentBootSucceeded;
BOOLEAN OslCurrentBootShutdown;
/* FUNCTIONS *****************************************************************/
VOID
OslFatalErrorEx (
_In_ ULONG ErrorCode,
_In_ ULONG Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3
)
{
/* For now just do this */
BlStatusPrint(L"FATAL ERROR IN ROSLOAD: %lx\n", ErrorCode);
}
VOID
OslAbortBoot (
_In_ NTSTATUS Status
)
{
/* For now just do this */
BlStatusPrint(L"BOOT ABORTED: %lx\n", Status);
}
NTSTATUS
OslBlStatusErrorHandler (
_In_ ULONG ErrorCode,
_In_ ULONG Parameter1,
_In_ ULONG_PTR Parameter2,
_In_ ULONG_PTR Parameter3,
_In_ ULONG_PTR Parameter4
)
{
/* We only filter error code 4 */
if (ErrorCode != 4)
{
return STATUS_NOT_IMPLEMENTED;
}
/* Handle error 4 as a fatal error 3 internally */
OslFatalErrorEx(3, Parameter1, Parameter2, Parameter3);
return STATUS_SUCCESS;
}
VOID
OslpSanitizeLoadOptionsString (
_In_ PWCHAR OptionString,
_In_ PWCHAR SanitizeString
)
{
/* TODO */
return;
}
VOID
OslpSanitizeStringOptions (
_In_ PBL_BCD_OPTION BcdOptions
)
{
/* TODO */
return;
}
NTSTATUS
OslpRemoveInternalApplicationOptions (
VOID
)
{
PWCHAR LoadString;
NTSTATUS Status;
/* Assume success */
Status = STATUS_SUCCESS;
/* Remove attempts to disable integrity checks or ELAM driver load */
BlRemoveBootOption(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_DisableIntegrityChecks);
BlRemoveBootOption(BlpApplicationEntry.BcdData,
BcdOSLoaderBoolean_DisableElamDrivers);
/* Get the command-line parameters, if any */
Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
BcdLibraryString_LoadOptionsString,
&LoadString);
if (NT_SUCCESS(Status))
{
/* Conver to upper case */
_wcsupr(LoadString);
/* Remove the existing one */
BlRemoveBootOption(BlpApplicationEntry.BcdData,
BcdLibraryString_LoadOptionsString);
/* Sanitize strings we don't want */
OslpSanitizeLoadOptionsString(LoadString, L"DISABLE_INTEGRITY_CHECKS");
OslpSanitizeLoadOptionsString(LoadString, L"NOINTEGRITYCHECKS");
OslpSanitizeLoadOptionsString(LoadString, L"DISABLEELAMDRIVERS");
/* Add the sanitized one back */
Status = BlAppendBootOptionString(&BlpApplicationEntry,
BcdLibraryString_LoadOptionsString,
LoadString);
/* Free the original BCD one */
BlMmFreeHeap(LoadString);
}
/* One more pass for secure-boot options */
OslpSanitizeStringOptions(BlpApplicationEntry.BcdData);
/* All good */
return Status;
}
NTSTATUS
OslpCheckForcedFailure (
VOID
)
{
ULONG64 ForceReason;
NTSTATUS Status;
/* Read the option */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdOSLoaderInteger_ForceFailure,
&ForceReason);
if (NT_SUCCESS(Status) && (ForceReason < 4))
{
/* For reasons above 3, don't actually do anything */
if (ForceReason > 3)
{
return STATUS_SUCCESS;
}
}
/* If the option isn't there or invalid, always return success */
return STATUS_SUCCESS;
}
VOID
OslpInitializeBootStatusDataLog (
VOID
)
{
/* TODO */
return;
}
NTSTATUS
OslpReadWriteBootStatusData (
_In_ BOOLEAN WriteAccess
)
{
/* Are you trying to write? */
if (WriteAccess)
{
/* Have we already read? */
if (!BsdBootStatusData)
{
/* No -- fail */
return STATUS_UNSUCCESSFUL;
}
}
else if (BsdBootStatusData)
{
/* No -- you're trying to read and we already have the data: no-op */
return STATUS_SUCCESS;
}
/* TODO */
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
OslpGetSetBootStatusData (
_In_ BOOLEAN Read,
_In_ RTL_BSD_ITEM_TYPE DataClass,
_Out_ PVOID Buffer,
_Inout_ PULONG Size
)
{
NTSTATUS Status;
ULONG Length, Offset;
/* No data has been read yet, fail */
if (!BsdBootStatusData)
{
return STATUS_UNSUCCESSFUL;
}
/* Invalid data item, fail */
if (DataClass >= RtlBsdItemMax)
{
return STATUS_INVALID_PARAMETER;
}
/* Capture the length and offset */
Length = OslpBootStatusFields[DataClass].Size;
Offset = OslpBootStatusFields[DataClass].Offset;
/* Make sure it doesn't overflow past the structure we've read */
if ((Length + Offset) > BsdBootStatusData->Version)
{
return STATUS_REVISION_MISMATCH;
}
/* Make sure we have enough space */
if (*Size >= Length)
{
/* We do -- is this a read? */
if (Read)
{
/* Yes, copy into the caller's buffer */
RtlCopyMemory(Buffer,
(PVOID)((ULONG_PTR)BsdBootStatusData + Offset),
Length);
}
else
{
/* It's a write, copy from caller's buffer */
RtlCopyMemory((PVOID)((ULONG_PTR)BsdBootStatusData + Offset),
Buffer,
Length);
}
/* Set success */
Status = STATUS_SUCCESS;
}
else
{
/* Return size needed and failure code */
*Size = Length;
Status = STATUS_BUFFER_TOO_SMALL;
}
/* All good */
return Status;
}
NTSTATUS
OslSetBootStatusData (
_In_ BOOLEAN LastBootGood,
_In_ BOOLEAN LastBootShutdown,
_In_ BOOLEAN LastBootCheckpoint,
_In_ ULONG UpdateIncrement,
_In_ ULONG BootAttemptCount
)
{
NTSTATUS Status;
ULONG Size;
/* Capture the BSD data in our globals, if needed */
Status = OslpReadWriteBootStatusData(FALSE);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Write last boot shutdown */
Size = sizeof(LastBootShutdown);
Status = OslpGetSetBootStatusData(FALSE,
RtlBsdItemBootShutdown,
&LastBootShutdown,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Write last boot good */
Size = sizeof(LastBootGood);
Status = OslpGetSetBootStatusData(FALSE,
RtlBsdItemBootGood,
&LastBootGood,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Write last boot checkpoint */
Size = sizeof(LastBootCheckpoint);
Status = OslpGetSetBootStatusData(FALSE,
RtlBsdItemBootCheckpoint,
&LastBootCheckpoint,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Write boot attempt count */
Size = sizeof(BootAttemptCount);
Status = OslpGetSetBootStatusData(FALSE,
RtlBsdItemBootAttemptCount,
&BootAttemptCount,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* TODO: Update Boot ID*/
/* Now write the data */
Status = OslpReadWriteBootStatusData(TRUE);
Quickie:
return Status;
}
NTSTATUS
OslGetBootStatusData (
_Out_ PBOOLEAN LastBootGood,
_Out_ PBOOLEAN LastBootShutdown,
_Out_ PBOOLEAN LastBootCheckpoint,
_Out_ PULONG LastBootId,
_Out_ PBOOLEAN BootGood,
_Out_ PBOOLEAN BootShutdown
)
{
NTSTATUS Status;
ULONG Size;
ULONG64 BootStatusPolicy;
BOOLEAN localBootShutdown, localBootGood;
/* Capture the BSD data in our globals, if needed */
Status = OslpReadWriteBootStatusData(FALSE);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Read the last boot ID */
Size = sizeof(*LastBootId);
Status = OslpGetSetBootStatusData(TRUE, RtlBsdItemBootId, LastBootId, &Size);
if (!NT_SUCCESS(Status))
{
/* Set to zero if we couldn't find it */
*LastBootId = 0;
}
/* Get the boot status policy */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdOSLoaderInteger_BootStatusPolicy,
&BootStatusPolicy);
if (!NT_SUCCESS(Status))
{
/* Apply a default if none exists */
BootStatusPolicy = IgnoreShutdownFailures;
}
/* Check if this was a good shutdown */
Size = sizeof(localBootShutdown);
Status = OslpGetSetBootStatusData(TRUE,
RtlBsdItemBootShutdown,
&localBootShutdown,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Tell the caller */
*BootShutdown = localBootShutdown;
/* Check if this was a good boot */
Size = sizeof(localBootGood);
Status = OslpGetSetBootStatusData(TRUE,
RtlBsdItemBootGood,
&localBootGood,
&Size);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Tell the caller*/
*BootGood = localBootGood;
/* TODO: Additional logic for checkpoints and such */
Status = STATUS_NOT_IMPLEMENTED;
Quickie:
return Status;
}
BOOLEAN
OslpAdvancedOptionsRequested (
VOID
)
{
/* TODO */
return FALSE;
}
NTSTATUS
OslPrepareTarget (
_Out_ PULONG ReturnFlags,
_Out_ PBOOLEAN Jump
)
{
PGUID AppId;
NTSTATUS Status;
PBL_DEVICE_DESCRIPTOR OsDevice;
PWCHAR SystemRoot;
SIZE_T RootLength, RootLengthWithSep;
ULONG i;
ULONG64 StartPerf, EndPerf;
RTL_BSD_DATA_POWER_TRANSITION PowerTransitionData;
PRTL_BSD_DATA_POWER_TRANSITION PowerBuffer;
ULONG OsDeviceHandle;
BOOLEAN LastBootGood, LastBootShutdown, LastBootCheckpoint;
ULONG BootId;
BOOLEAN BootGood, BootShutdown;
ULONG BsdSize;
/* Initialize locals */
PowerBuffer = NULL;
/* Assume no flags */
*ReturnFlags = 0;
/* Make all registry handles invalid */
OslImcHiveHandle = -1;
OslMachineHiveHandle = -1;
OslElamHiveHandle = -1;
OslSystemHiveHandle = -1;
/* Initialize memory lists */
InitializeListHead(&OslFreeMemoryDesctiptorsList);
InitializeListHead(&OslFinalMemoryMap);
InitializeListHead(&OslLoadedFirmwareDriverList);
for (i = 0; i < RTL_NUMBER_OF(OslCoreExtensionSubGroups); i++)
{
InitializeListHead(&OslCoreExtensionSubGroups[i]);
}
/* Initialize the memory map descriptor buffer */
RtlZeroMemory(&OslFinalMemoryMapDescriptorsBuffer,
sizeof(OslFinalMemoryMapDescriptorsBuffer));
/* Initialize general pointers */
OslLoadDevice = NULL;
OslLoadOptions = NULL;
OslSystemRoot = NULL;
OslLoaderBlock = NULL;
OslMemoryDescriptorBuffer = NULL;
/* Initialize general variables */
OslResetBootStatus = 0;
OslImcProcessingValid = FALSE;
OslFreeMemoryDesctiptorsListSize = 0;
/* Capture the current TSC */
StartPerf = BlArchGetPerformanceCounter();
/* Set our application type for SecureBoot/TPM purposes */
BlpSbdiCurrentApplicationType.Application.ObjectCode =
BCD_OBJECT_TYPE_APPLICATION;
BlpSbdiCurrentApplicationType.Application.ImageCode =
BCD_IMAGE_TYPE_BOOT_APP;
BlpSbdiCurrentApplicationType.Application.ApplicationCode =
BCD_APPLICATION_TYPE_OSLOADER;
BlpSbdiCurrentApplicationType.Application.Reserved = 0;
/* Register an error handler */
BlpStatusErrorHandler = OslBlStatusErrorHandler;
/* Get the application identifier and save it */
AppId = BlGetApplicationIdentifier();
if (AppId)
{
OslApplicationIdentifier = *AppId;
}
/* Enable tracing */
#ifdef BL_ETW_SUPPORT
TraceLoggingRegister(&TlgOslBootProviderProv);
#endif
/* Remove dangerous BCD options */
Status = OslpRemoveInternalApplicationOptions();
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* Get the OS device */
Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
BcdOSLoaderDevice_OSDevice,
&OsDevice,
0);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* If the OS device is the boot device, use the one provided by bootlib */
if (OsDevice->DeviceType == BootDevice)
{
OsDevice = BlpBootDevice;
}
/* Save it as a global for later */
OslLoadDevice = OsDevice;
/* Get the system root */
Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
BcdOSLoaderString_SystemRoot,
&SystemRoot);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
EfiPrintf(L"System root: %s\r\n", SystemRoot);
/* Get the system root length and make sure it's slash-terminated */
RootLength = wcslen(SystemRoot);
if (SystemRoot[RootLength - 1] == OBJ_NAME_PATH_SEPARATOR)
{
/* Perfect, set it */
OslSystemRoot = SystemRoot;
}
else
{
/* Allocate a new buffer large enough to contain the slash */
RootLengthWithSep = RootLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
OslSystemRoot = BlMmAllocateHeap(RootLengthWithSep * sizeof(WCHAR));
if (!OslSystemRoot)
{
/* Bail out if we're out of memory */
Status = STATUS_NO_MEMORY;
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* Make a copy of the path, adding the separator */
wcscpy(OslSystemRoot, SystemRoot);
wcscat(OslSystemRoot, L"\\");
/* Free the original one from the BCD library */
BlMmFreeHeap(SystemRoot);
}
/* Initialize access to the BSD */
OslpInitializeBootStatusDataLog();
/* Check if we're supposed to fail on purpose */
Status = OslpCheckForcedFailure();
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* Always disable VGA mode */
Status = BlAppendBootOptionBoolean(&BlpApplicationEntry,
BcdOSLoaderBoolean_DisableVgaMode,
TRUE);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* Get telemetry data from the last boot */
Status = OslGetBootStatusData(&LastBootGood,
&LastBootShutdown,
&LastBootCheckpoint,
&BootId,
&BootGood,
&BootShutdown);
if (!NT_SUCCESS(Status))
{
/* Assume this is the very first boot and everything went well */
BootId = 0;
LastBootGood = TRUE;
LastBootShutdown = TRUE;
LastBootCheckpoint = TRUE;
BootGood = TRUE;
BootShutdown = TRUE;
/* Set 0 boot attempts */
OslBootAttemptCount = 0;
}
/* Set more attempt variables to their initial state */
OslResetBootStatus = TRUE;
OslBootCountUpdateRequestForAbort = 0;
/* Read the current BSD data into the global buffer */
Status = OslpReadWriteBootStatusData(FALSE);
if (NT_SUCCESS(Status))
{
/* Get the power transition buffer from the BSD */
BsdSize = sizeof(PowerTransitionData);
Status = OslpGetSetBootStatusData(TRUE,
RtlBsdPowerTransition,
&PowerTransitionData,
&BsdSize);
if (NT_SUCCESS(Status))
{
/* Save the buffer */
PowerBuffer = &PowerTransitionData;
}
}
/* Check if this is VHD boot, which gets 3 boot attempts instead of 2 */
OslBootAttemptMaximum = 2;
OslBootAttemptMaximum += BlDeviceIsVirtualPartitionDevice(OslLoadDevice, NULL);
/* Check if the user wants to see the advanced menu */
if (!OslpAdvancedOptionsRequested())
{
/* The last boot failed more than the maximum */
if (!(LastBootGood) &&
(OslBootAttemptCount >= OslBootAttemptMaximum))
{
/* Return failure due to boot -- launch recovery */
*ReturnFlags |= 8;
/* Update the attempt count and status variables */
OslBootAttemptCount = OslBootAttemptMaximum - 1;
OslCurrentBootCheckpoint = LastBootCheckpoint;
OslCurrentBootSucceeded = FALSE;
OslCurrentBootShutdown = LastBootShutdown;
/* Crash with code 15 and abort boot */
OslFatalErrorEx(15, 0, 0, 0);
Status = STATUS_UNSUCCESSFUL;
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* We never made it far enough, more than the maximum */
if (!(LastBootCheckpoint) &&
(OslBootAttemptCount >= OslBootAttemptMaximum))
{
/* Return crash/dirty shutdown during boot attempt */
*ReturnFlags |= 0x10;
/* Update the attempt count and status variables */
OslBootAttemptCount = OslBootAttemptMaximum - 1;
OslCurrentBootSucceeded = LastBootGood;
OslCurrentBootShutdown = LastBootShutdown;
OslCurrentBootCheckpoint = FALSE;
/* Crash with code 16 and abort boot */
OslFatalErrorEx(16, 0, 0, 0);
Status = STATUS_UNSUCCESSFUL;
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* We failed to shutdown cleanly, and haven't booted yet */
if (!(LastBootShutdown) && !(OslBootAttemptCount))
{
/* Return crash/dirty shutdown */
*ReturnFlags |= 0x10;
/* There's no boot attempt, so only update shutdown variables */
OslCurrentBootSucceeded = LastBootGood;
OslCurrentBootShutdown = TRUE;
OslCurrentBootCheckpoint = LastBootCheckpoint;
/* Crash with code 16 and abort boot */
OslFatalErrorEx(16, 0, 0, 0);
Status = STATUS_UNSUCCESSFUL;
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
}
/* Officially increment the number of boot attempts */
OslBootAttemptCount++;
/* No success yet, write to boot status file */
OslCurrentBootCheckpoint = FALSE;
OslCurrentBootSucceeded = FALSE;
OslCurrentBootShutdown = FALSE;
OslSetBootStatusData(FALSE,
FALSE,
FALSE,
OslBootCountUpdateIncrement,
OslBootAttemptCount);
/* Open the OS Loader Device for Read/Write access */
Status = BlpDeviceOpen(OslLoadDevice,
BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
0,
&OsDeviceHandle);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Fail here: %d\r\n", __LINE__);
goto Quickie;
}
/* That's all for now, folks */
Status = STATUS_NOT_IMPLEMENTED;
DBG_UNREFERENCED_LOCAL_VARIABLE(PowerBuffer);
/* Printf perf */
EndPerf = BlArchGetPerformanceCounter();
EfiPrintf(L"Delta: %lld\r\n", EndPerf - StartPerf);
Quickie:
#if BL_BITLOCKER_SUPPORT
/* Destroy the RNG/AES library for BitLocker */
SymCryptRngAesUninstantiate();
#endif
/* Abort the boot */
OslAbortBoot(Status);
/* This is a failure path, so never do the jump */
*Jump = FALSE;
/* Return error code */
return Status;
}
NTSTATUS
OslFwpKernelSetupPhase1 (
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
OslArchpKernelSetupPhase0 (
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
return STATUS_NOT_IMPLEMENTED;
}
VOID
ArchRestoreProcessorFeatures (
VOID
)
{
/* Any XCR0 bits to clear? */
if (ArchXCr0BitsToClear)
{
/* Clear them */
#if defined(_MSC_VER) && !defined(__clang__)
__xsetbv(0, __xgetbv(0) & ~ArchXCr0BitsToClear);
#endif
ArchXCr0BitsToClear = 0;
}
/* Any CR4 bits to clear? */
if (ArchCr4BitsToClear)
{
/* Clear them */
__writecr4(__readcr4() & ~ArchCr4BitsToClear);
ArchCr4BitsToClear = 0;
}
}
NTSTATUS
OslArchKernelSetup (
_In_ ULONG Phase,
_In_ PLOADER_PARAMETER_BLOCK LoaderBlock
)
{
/* For phase 0, do architectural setup */
if (Phase == 0)
{
return OslArchpKernelSetupPhase0(LoaderBlock);
}
/* Nothing to do for Phase 1 */
if (Phase == 1)
{
return STATUS_SUCCESS;
}
/* Relocate the self map */
BlMmRelocateSelfMap();
/* Zero out the HAL Heap */
BlMmZeroVirtualAddressRange((PVOID)MM_HAL_VA_START,
MM_HAL_VA_END - MM_HAL_VA_START + 1);
/* Move shared user data in its place */
BlMmMoveVirtualAddressRange((PVOID)KI_USER_SHARED_DATA,
UserSharedAddress,
PAGE_SIZE);
/* Clear XCR0/CR4 CPU features that should be disabled before boot */
ArchRestoreProcessorFeatures();
/* Good to go */
return STATUS_SUCCESS;
}
NTSTATUS
OslExecuteTransition (
VOID
)
{
NTSTATUS Status;
/* Is the debugger meant to be kept enabled throughout the boot phase? */
if (!BdDebugAfterExitBootServices)
{
#ifdef BL_KD_SUPPORT
/* No -- disable it */
BlBdStop();
#endif
}
/* Setup Firmware for Phase 1 */
Status = OslFwpKernelSetupPhase1(OslLoaderBlock);
if (NT_SUCCESS(Status))
{
/* Setup kernel for Phase 2 */
Status = OslArchKernelSetup(2, OslLoaderBlock);
if (NT_SUCCESS(Status))
{
#ifdef BL_KD_SUPPORT
/* Stop the boot debugger */
BlBdStop();
#endif
/* Jump to the kernel entrypoint */
OslArchTransferToKernel(OslLoaderBlock, OslEntryPoint);
/* Infinite loop if we got here */
for (;;);
}
}
/* Return back with the failure code */
return Status;
}
NTSTATUS
OslpMain (
_Out_ PULONG ReturnFlags
)
{
CPU_INFO CpuInfo;
BOOLEAN NxEnabled;
NTSTATUS Status;
BOOLEAN ExecuteJump;
LARGE_INTEGER MiscMsr;
/* Check if the CPU supports NX */
BlArchCpuId(0x80000001, 0, &CpuInfo);
if (!(CpuInfo.Edx & 0x10000))
{
/* It doesn't, check if this is Intel */
EfiPrintf(L"NX disabled: %lx\r\n", CpuInfo.Edx);
if (BlArchGetCpuVendor() == CPU_INTEL)
{
/* Then turn off the MSR disable feature for it, enabling NX */
MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
EfiPrintf(L"NX being turned on: %llx\r\n", MiscMsr.QuadPart);
MiscMsr.HighPart &= MSR_XD_ENABLE_MASK;
MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
__writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
NxEnabled = TRUE;
}
}
/* Turn on NX support with the CPU-generic MSR */
__writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_NXE);
/* Load the kernel */
Status = OslPrepareTarget(ReturnFlags, &ExecuteJump);
if (NT_SUCCESS(Status) && (ExecuteJump))
{
/* Jump to the kernel */
Status = OslExecuteTransition();
}
/* Retore NX support */
__writemsr(MSR_EFER, __readmsr(MSR_EFER) ^ MSR_NXE);
/* Did we manually enable NX? */
if (NxEnabled)
{
/* Turn it back off */
MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
MiscMsr.HighPart |= ~MSR_XD_ENABLE_MASK;
__writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
}
/* Go back */
return Status;
}
/*++
* @name OslMain
*
* The OslMain function implements the Windows Boot Application entrypoint for
* the OS Loader.
*
* @param BootParameters
* Pointer to the Boot Application Parameter Block.
*
* @return NT_SUCCESS if the image was loaded correctly, relevant error code
* otherwise.
*
*--*/
NTSTATUS
NTAPI
OslMain (
_In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
)
{
BL_LIBRARY_PARAMETERS LibraryParameters;
NTSTATUS Status;
PBL_RETURN_ARGUMENTS ReturnArguments;
PBL_APPLICATION_ENTRY AppEntry;
CPU_INFO CpuInfo;
ULONG Flags;
/* Get the return arguments structure, and set our version */
ReturnArguments = (PBL_RETURN_ARGUMENTS)((ULONG_PTR)BootParameters +
BootParameters->ReturnArgumentsOffset);
ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
/* Get the application entry, and validate it */
AppEntry = (PBL_APPLICATION_ENTRY)((ULONG_PTR)BootParameters +
BootParameters->AppEntryOffset);
if (!RtlEqualMemory(AppEntry->Signature,
BL_APP_ENTRY_SIGNATURE,
sizeof(AppEntry->Signature)))
{
/* Unrecognized, bail out */
Status = STATUS_INVALID_PARAMETER_9;
goto Quickie;
}
/* Check if CPUID 01h is supported */
if (BlArchIsCpuIdFunctionSupported(1))
{
/* Query CPU features */
BlArchCpuId(1, 0, &CpuInfo);
/* Check if PAE is supported */
if (CpuInfo.Edx & 0x40)
{
EfiPrintf(L"PAE Supported, but won't be used\r\n");
}
}
/* Setup the boot library parameters for this application */
BlSetupDefaultParameters(&LibraryParameters);
LibraryParameters.TranslationType = BlVirtual;
LibraryParameters.LibraryFlags = BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE |
BL_LIBRARY_FLAG_REINITIALIZE_ALL;
LibraryParameters.MinimumAllocationCount = 1024;
LibraryParameters.MinimumHeapSize = 2 * 1024 * 1024;
LibraryParameters.HeapAllocationAttributes = BlMemoryKernelRange;
LibraryParameters.FontBaseDirectory = L"\\Reactos\\Boot\\Fonts";
LibraryParameters.DescriptorCount = 512;
/* Initialize the boot library */
Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
if (NT_SUCCESS(Status))
{
/* For testing, draw the logo */
OslDrawLogo();
/* Call the main routine */
Status = OslpMain(&Flags);
/* Return the flags, and destroy the boot library */
ReturnArguments->Flags = Flags;
BlDestroyLibrary();
}
Quickie:
/* Return back to boot manager */
ReturnArguments->Status = Status;
return Status;
}