/* * 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; /* 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 * * 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; }