[ROSLOAD] Fix clang-cl build.
[reactos.git] / boot / environ / app / rosload / rosload.c
index 000cbee..9eda2d3 100644 (file)
 
 #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;
+
 /* 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 = BlAppendBootOptionsString(&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
+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;
+
+    /* 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();
+
+#ifdef BL_TPM_SUPPORT
+    BlpSbdiCurrentApplicationType = 0x10200003;
+#endif
+
+    /* 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))
+    {
+        goto Quickie;
+    }
+
+    /* Get the OS device */
+    Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
+                                   BcdOSLoaderDevice_OSDevice,
+                                   &OsDevice,
+                                   0);
+    if (!NT_SUCCESS(Status))
+    {
+        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))
+    {
+        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;
+            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);
+    }
+
+    Status = STATUS_NOT_IMPLEMENTED;
+
+    /* 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
  *
@@ -33,7 +511,72 @@ OslMain (
     _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
     )
 {
-    EfiPrintf(L"ReactOS UEFI OS Loader Initializing...\r\n");
-    return STATUS_NOT_IMPLEMENTED;
+    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;
 }