9eda2d31fec3dbe4869e2f48eb9a8e882380ebd1
[reactos.git] / boot / environ / app / rosload / rosload.c
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 /* FUNCTIONS *****************************************************************/
54
55 VOID
56 OslFatalErrorEx (
57 _In_ ULONG ErrorCode,
58 _In_ ULONG Parameter1,
59 _In_ ULONG_PTR Parameter2,
60 _In_ ULONG_PTR Parameter3
61 )
62 {
63 /* For now just do this */
64 BlStatusPrint(L"FATAL ERROR IN ROSLOAD: %lx\n", ErrorCode);
65 }
66
67 VOID
68 OslAbortBoot (
69 _In_ NTSTATUS Status
70 )
71 {
72 /* For now just do this */
73 BlStatusPrint(L"BOOT ABORTED: %lx\n", Status);
74 }
75
76 NTSTATUS
77 OslBlStatusErrorHandler (
78 _In_ ULONG ErrorCode,
79 _In_ ULONG Parameter1,
80 _In_ ULONG_PTR Parameter2,
81 _In_ ULONG_PTR Parameter3,
82 _In_ ULONG_PTR Parameter4
83 )
84 {
85 /* We only filter error code 4 */
86 if (ErrorCode != 4)
87 {
88 return STATUS_NOT_IMPLEMENTED;
89 }
90
91 /* Handle error 4 as a fatal error 3 internally */
92 OslFatalErrorEx(3, Parameter1, Parameter2, Parameter3);
93 return STATUS_SUCCESS;
94 }
95
96 VOID
97 OslpSanitizeLoadOptionsString (
98 _In_ PWCHAR OptionString,
99 _In_ PWCHAR SanitizeString
100 )
101 {
102 /* TODO */
103 return;
104 }
105
106 VOID
107 OslpSanitizeStringOptions (
108 _In_ PBL_BCD_OPTION BcdOptions
109 )
110 {
111 /* TODO */
112 return;
113 }
114
115 NTSTATUS
116 OslpRemoveInternalApplicationOptions (
117 VOID
118 )
119 {
120 PWCHAR LoadString;
121 NTSTATUS Status;
122
123 /* Assume success */
124 Status = STATUS_SUCCESS;
125
126 /* Remove attempts to disable integrity checks or ELAM driver load */
127 BlRemoveBootOption(BlpApplicationEntry.BcdData,
128 BcdLibraryBoolean_DisableIntegrityChecks);
129 BlRemoveBootOption(BlpApplicationEntry.BcdData,
130 BcdOSLoaderBoolean_DisableElamDrivers);
131
132 /* Get the command-line parameters, if any */
133 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
134 BcdLibraryString_LoadOptionsString,
135 &LoadString);
136 if (NT_SUCCESS(Status))
137 {
138 /* Conver to upper case */
139 _wcsupr(LoadString);
140
141 /* Remove the existing one */
142 //BlRemoveBootOption(BlpApplicationEntry.BcdData,
143 // BcdLibraryString_LoadOptionsString);
144
145 /* Sanitize strings we don't want */
146 OslpSanitizeLoadOptionsString(LoadString, L"DISABLE_INTEGRITY_CHECKS");
147 OslpSanitizeLoadOptionsString(LoadString, L"NOINTEGRITYCHECKS");
148 OslpSanitizeLoadOptionsString(LoadString, L"DISABLEELAMDRIVERS");
149
150 /* Add the sanitized one back */
151 //Status = BlAppendBootOptionsString(&BlpApplicationEntry,
152 // BcdLibraryString_LoadOptionsString,
153 // LoadString);
154
155 /* Free the original BCD one */
156 BlMmFreeHeap(LoadString);
157 }
158
159 /* One more pass for secure-boot options */
160 OslpSanitizeStringOptions(BlpApplicationEntry.BcdData);
161
162 /* All good */
163 return Status;
164 }
165
166 NTSTATUS
167 OslPrepareTarget (
168 _Out_ PULONG ReturnFlags,
169 _Out_ PBOOLEAN Jump
170 )
171 {
172 PGUID AppId;
173 NTSTATUS Status;
174 PBL_DEVICE_DESCRIPTOR OsDevice;
175 PWCHAR SystemRoot;
176 SIZE_T RootLength, RootLengthWithSep;
177 ULONG i;
178 ULONG64 StartPerf, EndPerf;
179
180 /* Assume no flags */
181 *ReturnFlags = 0;
182
183 /* Make all registry handles invalid */
184 OslImcHiveHandle = -1;
185 OslMachineHiveHandle = -1;
186 OslElamHiveHandle = -1;
187 OslSystemHiveHandle = -1;
188
189 /* Initialize memory lists */
190 InitializeListHead(&OslFreeMemoryDesctiptorsList);
191 InitializeListHead(&OslFinalMemoryMap);
192 InitializeListHead(&OslLoadedFirmwareDriverList);
193 for (i = 0; i < RTL_NUMBER_OF(OslCoreExtensionSubGroups); i++)
194 {
195 InitializeListHead(&OslCoreExtensionSubGroups[i]);
196 }
197
198 /* Initialize the memory map descriptor buffer */
199 RtlZeroMemory(&OslFinalMemoryMapDescriptorsBuffer,
200 sizeof(OslFinalMemoryMapDescriptorsBuffer));
201
202 /* Initialize general pointers */
203 OslLoadDevice = NULL;
204 OslLoadOptions = NULL;
205 OslSystemRoot = NULL;
206 OslLoaderBlock = NULL;
207 OslMemoryDescriptorBuffer = NULL;
208
209 /* Initialize general variables */
210 OslResetBootStatus = 0;
211 OslImcProcessingValid = FALSE;
212 OslFreeMemoryDesctiptorsListSize = 0;
213
214 /* Capture the current TSC */
215 StartPerf = BlArchGetPerformanceCounter();
216
217 #ifdef BL_TPM_SUPPORT
218 BlpSbdiCurrentApplicationType = 0x10200003;
219 #endif
220
221 /* Register an error handler */
222 BlpStatusErrorHandler = OslBlStatusErrorHandler;
223
224 /* Get the application identifier and save it */
225 AppId = BlGetApplicationIdentifier();
226 if (AppId)
227 {
228 OslApplicationIdentifier = *AppId;
229 }
230
231 /* Enable tracing */
232 #ifdef BL_ETW_SUPPORT
233 TraceLoggingRegister(&TlgOslBootProviderProv);
234 #endif
235
236 /* Remove dangerous BCD options */
237 Status = OslpRemoveInternalApplicationOptions();
238 if (!NT_SUCCESS(Status))
239 {
240 goto Quickie;
241 }
242
243 /* Get the OS device */
244 Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData,
245 BcdOSLoaderDevice_OSDevice,
246 &OsDevice,
247 0);
248 if (!NT_SUCCESS(Status))
249 {
250 goto Quickie;
251 }
252
253 /* If the OS device is the boot device, use the one provided by bootlib */
254 if (OsDevice->DeviceType == BootDevice)
255 {
256 OsDevice = BlpBootDevice;
257 }
258
259 /* Save it as a global for later */
260 OslLoadDevice = OsDevice;
261
262 /* Get the system root */
263 Status = BlGetBootOptionString(BlpApplicationEntry.BcdData,
264 BcdOSLoaderString_SystemRoot,
265 &SystemRoot);
266 if (!NT_SUCCESS(Status))
267 {
268 goto Quickie;
269 }
270
271 EfiPrintf(L"System root: %s\r\n", SystemRoot);
272
273 /* Get the system root length and make sure it's slash-terminated */
274 RootLength = wcslen(SystemRoot);
275 if (SystemRoot[RootLength - 1] == OBJ_NAME_PATH_SEPARATOR)
276 {
277 /* Perfect, set it */
278 OslSystemRoot = SystemRoot;
279 }
280 else
281 {
282 /* Allocate a new buffer large enough to contain the slash */
283 RootLengthWithSep = RootLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
284 OslSystemRoot = BlMmAllocateHeap(RootLengthWithSep * sizeof(WCHAR));
285 if (!OslSystemRoot)
286 {
287 /* Bail out if we're out of memory */
288 Status = STATUS_NO_MEMORY;
289 goto Quickie;
290 }
291
292 /* Make a copy of the path, adding the separator */
293 wcscpy(OslSystemRoot, SystemRoot);
294 wcscat(OslSystemRoot, L"\\");
295
296 /* Free the original one from the BCD library */
297 BlMmFreeHeap(SystemRoot);
298 }
299
300 Status = STATUS_NOT_IMPLEMENTED;
301
302 /* Printf perf */
303 EndPerf = BlArchGetPerformanceCounter();
304 EfiPrintf(L"Delta: %lld\r\n", EndPerf - StartPerf);
305
306 Quickie:
307 #if BL_BITLOCKER_SUPPORT
308 /* Destroy the RNG/AES library for BitLocker */
309 SymCryptRngAesUninstantiate();
310 #endif
311
312 /* Abort the boot */
313 OslAbortBoot(Status);
314
315 /* This is a failure path, so never do the jump */
316 *Jump = FALSE;
317
318 /* Return error code */
319 return Status;
320 }
321
322 NTSTATUS
323 OslFwpKernelSetupPhase1 (
324 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
325 )
326 {
327 return STATUS_NOT_IMPLEMENTED;
328 }
329
330 NTSTATUS
331 OslArchpKernelSetupPhase0 (
332 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
333 )
334 {
335 return STATUS_NOT_IMPLEMENTED;
336 }
337
338 VOID
339 ArchRestoreProcessorFeatures (
340 VOID
341 )
342 {
343 /* Any XCR0 bits to clear? */
344 if (ArchXCr0BitsToClear)
345 {
346 /* Clear them */
347 #if defined(_MSC_VER) && !defined(__clang__)
348 __xsetbv(0, __xgetbv(0) & ~ArchXCr0BitsToClear);
349 #endif
350 ArchXCr0BitsToClear = 0;
351 }
352
353 /* Any CR4 bits to clear? */
354 if (ArchCr4BitsToClear)
355 {
356 /* Clear them */
357 __writecr4(__readcr4() & ~ArchCr4BitsToClear);
358 ArchCr4BitsToClear = 0;
359 }
360 }
361
362 NTSTATUS
363 OslArchKernelSetup (
364 _In_ ULONG Phase,
365 _In_ PLOADER_PARAMETER_BLOCK LoaderBlock
366 )
367 {
368 /* For phase 0, do architectural setup */
369 if (Phase == 0)
370 {
371 return OslArchpKernelSetupPhase0(LoaderBlock);
372 }
373
374 /* Nothing to do for Phase 1 */
375 if (Phase == 1)
376 {
377 return STATUS_SUCCESS;
378 }
379
380 /* Relocate the self map */
381 BlMmRelocateSelfMap();
382
383 /* Zero out the HAL Heap */
384 BlMmZeroVirtualAddressRange((PVOID)MM_HAL_VA_START,
385 MM_HAL_VA_END - MM_HAL_VA_START + 1);
386
387 /* Move shared user data in its place */
388 BlMmMoveVirtualAddressRange((PVOID)KI_USER_SHARED_DATA,
389 UserSharedAddress,
390 PAGE_SIZE);
391
392 /* Clear XCR0/CR4 CPU features that should be disabled before boot */
393 ArchRestoreProcessorFeatures();
394
395 /* Good to go */
396 return STATUS_SUCCESS;
397 }
398
399 NTSTATUS
400 OslExecuteTransition (
401 VOID
402 )
403 {
404 NTSTATUS Status;
405
406 /* Is the debugger meant to be kept enabled throughout the boot phase? */
407 if (!BdDebugAfterExitBootServices)
408 {
409 #ifdef BL_KD_SUPPORT
410 /* No -- disable it */
411 BlBdStop();
412 #endif
413 }
414
415 /* Setup Firmware for Phase 1 */
416 Status = OslFwpKernelSetupPhase1(OslLoaderBlock);
417 if (NT_SUCCESS(Status))
418 {
419 /* Setup kernel for Phase 2 */
420 Status = OslArchKernelSetup(2, OslLoaderBlock);
421 if (NT_SUCCESS(Status))
422 {
423 #ifdef BL_KD_SUPPORT
424 /* Stop the boot debugger */
425 BlBdStop();
426 #endif
427 /* Jump to the kernel entrypoint */
428 OslArchTransferToKernel(OslLoaderBlock, OslEntryPoint);
429
430 /* Infinite loop if we got here */
431 for (;;);
432 }
433 }
434
435 /* Return back with the failure code */
436 return Status;
437 }
438
439 NTSTATUS
440 OslpMain (
441 _Out_ PULONG ReturnFlags
442 )
443 {
444 CPU_INFO CpuInfo;
445 BOOLEAN NxEnabled;
446 NTSTATUS Status;
447 BOOLEAN ExecuteJump;
448 LARGE_INTEGER MiscMsr;
449
450 /* Check if the CPU supports NX */
451 BlArchCpuId(0x80000001, 0, &CpuInfo);
452 if (!(CpuInfo.Edx & 0x10000))
453 {
454 /* It doesn't, check if this is Intel */
455 EfiPrintf(L"NX disabled: %lx\r\n", CpuInfo.Edx);
456 if (BlArchGetCpuVendor() == CPU_INTEL)
457 {
458 /* Then turn off the MSR disable feature for it, enabling NX */
459 MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
460 EfiPrintf(L"NX being turned on: %llx\r\n", MiscMsr.QuadPart);
461 MiscMsr.HighPart &= MSR_XD_ENABLE_MASK;
462 MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
463 __writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
464 NxEnabled = TRUE;
465 }
466 }
467
468 /* Turn on NX support with the CPU-generic MSR */
469 __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_NXE);
470
471 /* Load the kernel */
472 Status = OslPrepareTarget(ReturnFlags, &ExecuteJump);
473 if (NT_SUCCESS(Status) && (ExecuteJump))
474 {
475 /* Jump to the kernel */
476 Status = OslExecuteTransition();
477 }
478
479 /* Retore NX support */
480 __writemsr(MSR_EFER, __readmsr(MSR_EFER) ^ MSR_NXE);
481
482 /* Did we manually enable NX? */
483 if (NxEnabled)
484 {
485 /* Turn it back off */
486 MiscMsr.QuadPart = __readmsr(MSR_IA32_MISC_ENABLE);
487 MiscMsr.HighPart |= ~MSR_XD_ENABLE_MASK;
488 __writemsr(MSR_IA32_MISC_ENABLE, MiscMsr.QuadPart);
489 }
490
491 /* Go back */
492 return Status;
493 }
494
495 /*++
496 * @name OslMain
497 *
498 * The OslMain function implements the Windows Boot Application entrypoint for
499 * the OS Loader.
500 *
501 * @param BootParameters
502 * Pointer to the Boot Application Parameter Block.
503 *
504 * @return NT_SUCCESS if the image was loaded correctly, relevant error code
505 * otherwise.
506 *
507 *--*/
508 NTSTATUS
509 NTAPI
510 OslMain (
511 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
512 )
513 {
514 BL_LIBRARY_PARAMETERS LibraryParameters;
515 NTSTATUS Status;
516 PBL_RETURN_ARGUMENTS ReturnArguments;
517 PBL_APPLICATION_ENTRY AppEntry;
518 CPU_INFO CpuInfo;
519 ULONG Flags;
520
521 /* Get the return arguments structure, and set our version */
522 ReturnArguments = (PBL_RETURN_ARGUMENTS)((ULONG_PTR)BootParameters +
523 BootParameters->ReturnArgumentsOffset);
524 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
525
526 /* Get the application entry, and validate it */
527 AppEntry = (PBL_APPLICATION_ENTRY)((ULONG_PTR)BootParameters +
528 BootParameters->AppEntryOffset);
529 if (!RtlEqualMemory(AppEntry->Signature,
530 BL_APP_ENTRY_SIGNATURE,
531 sizeof(AppEntry->Signature)))
532 {
533 /* Unrecognized, bail out */
534 Status = STATUS_INVALID_PARAMETER_9;
535 goto Quickie;
536 }
537
538 /* Check if CPUID 01h is supported */
539 if (BlArchIsCpuIdFunctionSupported(1))
540 {
541 /* Query CPU features */
542 BlArchCpuId(1, 0, &CpuInfo);
543
544 /* Check if PAE is supported */
545 if (CpuInfo.Edx & 0x40)
546 {
547 EfiPrintf(L"PAE Supported, but won't be used\r\n");
548 }
549 }
550
551 /* Setup the boot library parameters for this application */
552 BlSetupDefaultParameters(&LibraryParameters);
553 LibraryParameters.TranslationType = BlVirtual;
554 LibraryParameters.LibraryFlags = BL_LIBRARY_FLAG_ZERO_HEAP_ALLOCATIONS_ON_FREE |
555 BL_LIBRARY_FLAG_REINITIALIZE_ALL;
556 LibraryParameters.MinimumAllocationCount = 1024;
557 LibraryParameters.MinimumHeapSize = 2 * 1024 * 1024;
558 LibraryParameters.HeapAllocationAttributes = BlMemoryKernelRange;
559 LibraryParameters.FontBaseDirectory = L"\\Reactos\\Boot\\Fonts";
560 LibraryParameters.DescriptorCount = 512;
561
562 /* Initialize the boot library */
563 Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
564 if (NT_SUCCESS(Status))
565 {
566 /* For testing, draw the logo */
567 OslDrawLogo();
568
569 /* Call the main routine */
570 Status = OslpMain(&Flags);
571
572 /* Return the flags, and destroy the boot library */
573 ReturnArguments->Flags = Flags;
574 BlDestroyLibrary();
575 }
576
577 Quickie:
578 /* Return back to boot manager */
579 ReturnArguments->Status = Status;
580 return Status;
581 }
582