xref: /reactos/ntoskrnl/io/iomgr/iomgr.c (revision 2d4c0b87)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel
4  * FILE:            ntoskrnl/io/iomgr/iomgr.c
5  * PURPOSE:         I/O Manager Initialization and Misc Utility Functions
6  *
7  * PROGRAMMERS:     David Welch (welch@mcmail.com)
8  */
9 
10 /* INCLUDES ****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 ULONG IopTraceLevel = 0;
17 BOOLEAN PnpSystemInit = FALSE;
18 
19 VOID
20 NTAPI
21 IopTimerDispatch(
22     IN PKDPC Dpc,
23     IN PVOID DeferredContext,
24     IN PVOID SystemArgument1,
25     IN PVOID SystemArgument2
26 );
27 
28 BOOLEAN
29 NTAPI
30 WmiInitialize(
31     VOID);
32 
33 /* DATA ********************************************************************/
34 
35 POBJECT_TYPE IoDeviceObjectType = NULL;
36 POBJECT_TYPE IoFileObjectType = NULL;
37 extern POBJECT_TYPE IoControllerObjectType;
38 BOOLEAN IoCountOperations = TRUE;
39 ULONG IoReadOperationCount = 0;
40 LARGE_INTEGER IoReadTransferCount = {{0, 0}};
41 ULONG IoWriteOperationCount = 0;
42 LARGE_INTEGER IoWriteTransferCount = {{0, 0}};
43 ULONG IoOtherOperationCount = 0;
44 LARGE_INTEGER IoOtherTransferCount = {{0, 0}};
45 KSPIN_LOCK IoStatisticsLock = 0;
46 ULONG IopAutoReboot;
47 ULONG IopNumTriageDumpDataBlocks;
48 PVOID IopTriageDumpDataBlocks[64];
49 
50 GENERIC_MAPPING IopFileMapping = {
51     FILE_GENERIC_READ,
52     FILE_GENERIC_WRITE,
53     FILE_GENERIC_EXECUTE,
54     FILE_ALL_ACCESS};
55 
56 extern LIST_ENTRY ShutdownListHead;
57 extern LIST_ENTRY LastChanceShutdownListHead;
58 extern KSPIN_LOCK ShutdownListLock;
59 extern POBJECT_TYPE IoAdapterObjectType;
60 extern ERESOURCE IopDatabaseResource;
61 ERESOURCE IopSecurityResource;
62 extern ERESOURCE IopDriverLoadResource;
63 extern LIST_ENTRY IopDiskFileSystemQueueHead;
64 extern LIST_ENTRY IopCdRomFileSystemQueueHead;
65 extern LIST_ENTRY IopTapeFileSystemQueueHead;
66 extern LIST_ENTRY IopNetworkFileSystemQueueHead;
67 extern LIST_ENTRY DriverBootReinitListHead;
68 extern LIST_ENTRY DriverReinitListHead;
69 extern LIST_ENTRY IopFsNotifyChangeQueueHead;
70 extern LIST_ENTRY IopErrorLogListHead;
71 extern LIST_ENTRY IopTimerQueueHead;
72 extern KDPC IopTimerDpc;
73 extern KTIMER IopTimer;
74 extern KSPIN_LOCK IoStatisticsLock;
75 extern KSPIN_LOCK DriverReinitListLock;
76 extern KSPIN_LOCK DriverBootReinitListLock;
77 extern KSPIN_LOCK IopLogListLock;
78 extern KSPIN_LOCK IopTimerLock;
79 
80 extern PDEVICE_OBJECT IopErrorLogObject;
81 extern BOOLEAN PnPBootDriversInitialized;
82 
83 GENERAL_LOOKASIDE IoLargeIrpLookaside;
84 GENERAL_LOOKASIDE IoSmallIrpLookaside;
85 GENERAL_LOOKASIDE IopMdlLookasideList;
86 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside;
87 
88 PLOADER_PARAMETER_BLOCK IopLoaderBlock;
89 
90 /* INIT FUNCTIONS ************************************************************/
91 
92 CODE_SEG("INIT")
93 VOID
94 NTAPI
95 IopInitLookasideLists(VOID)
96 {
97     ULONG LargeIrpSize, SmallIrpSize, MdlSize;
98     LONG i;
99     PKPRCB Prcb;
100     PGENERAL_LOOKASIDE CurrentList = NULL;
101 
102     /* Calculate the sizes */
103     LargeIrpSize = sizeof(IRP) + (8 * sizeof(IO_STACK_LOCATION));
104     SmallIrpSize = sizeof(IRP) + sizeof(IO_STACK_LOCATION);
105     MdlSize = sizeof(MDL) + (23 * sizeof(PFN_NUMBER));
106 
107     /* Initialize the Lookaside List for I\O Completion */
108     ExInitializeSystemLookasideList(&IoCompletionPacketLookaside,
109                                     NonPagedPool,
110                                     sizeof(IOP_MINI_COMPLETION_PACKET),
111                                     IOC_TAG1,
112                                     32,
113                                     &ExSystemLookasideListHead);
114 
115     /* Initialize the Lookaside List for Large IRPs */
116     ExInitializeSystemLookasideList(&IoLargeIrpLookaside,
117                                     NonPagedPool,
118                                     LargeIrpSize,
119                                     IO_LARGEIRP,
120                                     64,
121                                     &ExSystemLookasideListHead);
122 
123 
124     /* Initialize the Lookaside List for Small IRPs */
125     ExInitializeSystemLookasideList(&IoSmallIrpLookaside,
126                                     NonPagedPool,
127                                     SmallIrpSize,
128                                     IO_SMALLIRP,
129                                     32,
130                                     &ExSystemLookasideListHead);
131 
132     /* Initialize the Lookaside List for MDLs */
133     ExInitializeSystemLookasideList(&IopMdlLookasideList,
134                                     NonPagedPool,
135                                     MdlSize,
136                                     TAG_MDL,
137                                     128,
138                                     &ExSystemLookasideListHead);
139 
140     /* Allocate the global lookaside list buffer */
141     CurrentList = ExAllocatePoolWithTag(NonPagedPool,
142                                         4 * KeNumberProcessors *
143                                         sizeof(GENERAL_LOOKASIDE),
144                                         TAG_IO);
145 
146     /* Loop all processors */
147     for (i = 0; i < KeNumberProcessors; i++)
148     {
149         /* Get the PRCB for this CPU */
150         Prcb = KiProcessorBlock[i];
151         DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i, Prcb);
152 
153         /* Write IRP credit limit */
154         Prcb->LookasideIrpFloat = 512 / KeNumberProcessors;
155 
156         /* Set the I/O Completion List */
157         Prcb->PPLookasideList[LookasideCompletionList].L = &IoCompletionPacketLookaside;
158         if (CurrentList)
159         {
160             /* Initialize the Lookaside List for mini-packets */
161             ExInitializeSystemLookasideList(CurrentList,
162                                             NonPagedPool,
163                                             sizeof(IOP_MINI_COMPLETION_PACKET),
164                                             IO_SMALLIRP_CPU,
165                                             32,
166                                             &ExSystemLookasideListHead);
167             Prcb->PPLookasideList[LookasideCompletionList].P = CurrentList;
168             CurrentList++;
169 
170         }
171         else
172         {
173             Prcb->PPLookasideList[LookasideCompletionList].P = &IoCompletionPacketLookaside;
174         }
175 
176         /* Set the Large IRP List */
177         Prcb->PPLookasideList[LookasideLargeIrpList].L = &IoLargeIrpLookaside;
178         if (CurrentList)
179         {
180             /* Initialize the Lookaside List for Large IRPs */
181             ExInitializeSystemLookasideList(CurrentList,
182                                             NonPagedPool,
183                                             LargeIrpSize,
184                                             IO_LARGEIRP_CPU,
185                                             64,
186                                             &ExSystemLookasideListHead);
187             Prcb->PPLookasideList[LookasideLargeIrpList].P = CurrentList;
188             CurrentList++;
189 
190         }
191         else
192         {
193             Prcb->PPLookasideList[LookasideLargeIrpList].P = &IoLargeIrpLookaside;
194         }
195 
196         /* Set the Small IRP List */
197         Prcb->PPLookasideList[LookasideSmallIrpList].L = &IoSmallIrpLookaside;
198         if (CurrentList)
199         {
200             /* Initialize the Lookaside List for Small IRPs */
201             ExInitializeSystemLookasideList(CurrentList,
202                                             NonPagedPool,
203                                             SmallIrpSize,
204                                             IO_SMALLIRP_CPU,
205                                             32,
206                                             &ExSystemLookasideListHead);
207             Prcb->PPLookasideList[LookasideSmallIrpList].P = CurrentList;
208             CurrentList++;
209 
210         }
211         else
212         {
213             Prcb->PPLookasideList[LookasideSmallIrpList].P = &IoSmallIrpLookaside;
214         }
215 
216         /* Set the MDL Completion List */
217         Prcb->PPLookasideList[LookasideMdlList].L = &IopMdlLookasideList;
218         if (CurrentList)
219         {
220             /* Initialize the Lookaside List for MDLs */
221             ExInitializeSystemLookasideList(CurrentList,
222                                             NonPagedPool,
223                                             SmallIrpSize,
224                                             TAG_MDL,
225                                             128,
226                                             &ExSystemLookasideListHead);
227 
228             Prcb->PPLookasideList[LookasideMdlList].P = CurrentList;
229             CurrentList++;
230 
231         }
232         else
233         {
234             Prcb->PPLookasideList[LookasideMdlList].P = &IopMdlLookasideList;
235         }
236     }
237 }
238 
239 CODE_SEG("INIT")
240 BOOLEAN
241 NTAPI
242 IopCreateObjectTypes(VOID)
243 {
244     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
245     UNICODE_STRING Name;
246 
247     /* Initialize default settings */
248     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
249     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
250     ObjectTypeInitializer.PoolType = NonPagedPool;
251     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
252     ObjectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
253     ObjectTypeInitializer.UseDefaultObject = TRUE;
254     ObjectTypeInitializer.GenericMapping = IopFileMapping;
255 
256     /* Do the Adapter Type */
257     RtlInitUnicodeString(&Name, L"Adapter");
258     if (!NT_SUCCESS(ObCreateObjectType(&Name,
259                                        &ObjectTypeInitializer,
260                                        NULL,
261                                        &IoAdapterObjectType))) return FALSE;
262 
263     /* Do the Controller Type */
264     RtlInitUnicodeString(&Name, L"Controller");
265     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CONTROLLER_OBJECT);
266     if (!NT_SUCCESS(ObCreateObjectType(&Name,
267                                        &ObjectTypeInitializer,
268                                        NULL,
269                                        &IoControllerObjectType))) return FALSE;
270 
271     /* Do the Device Type */
272     RtlInitUnicodeString(&Name, L"Device");
273     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DEVICE_OBJECT);
274     ObjectTypeInitializer.DeleteProcedure = IopDeleteDevice;
275     ObjectTypeInitializer.ParseProcedure = IopParseDevice;
276     ObjectTypeInitializer.SecurityProcedure = IopGetSetSecurityObject;
277     ObjectTypeInitializer.CaseInsensitive = TRUE;
278     if (!NT_SUCCESS(ObCreateObjectType(&Name,
279                                        &ObjectTypeInitializer,
280                                        NULL,
281                                        &IoDeviceObjectType))) return FALSE;
282 
283     /* Initialize the Driver object type */
284     RtlInitUnicodeString(&Name, L"Driver");
285     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DRIVER_OBJECT);
286     ObjectTypeInitializer.DeleteProcedure = IopDeleteDriver;
287     ObjectTypeInitializer.ParseProcedure = NULL;
288     ObjectTypeInitializer.SecurityProcedure = NULL;
289     if (!NT_SUCCESS(ObCreateObjectType(&Name,
290                                        &ObjectTypeInitializer,
291                                        NULL,
292                                        &IoDriverObjectType))) return FALSE;
293 
294     /* Initialize the I/O Completion object type */
295     RtlInitUnicodeString(&Name, L"IoCompletion");
296     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KQUEUE);
297     ObjectTypeInitializer.ValidAccessMask = IO_COMPLETION_ALL_ACCESS;
298     ObjectTypeInitializer.InvalidAttributes |= OBJ_PERMANENT;
299     ObjectTypeInitializer.GenericMapping = IopCompletionMapping;
300     ObjectTypeInitializer.DeleteProcedure = IopDeleteIoCompletion;
301     if (!NT_SUCCESS(ObCreateObjectType(&Name,
302                                        &ObjectTypeInitializer,
303                                        NULL,
304                                        &IoCompletionType))) return FALSE;
305 
306     /* Initialize the File object type  */
307     RtlInitUnicodeString(&Name, L"File");
308     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FILE_OBJECT);
309     ObjectTypeInitializer.InvalidAttributes |= OBJ_EXCLUSIVE;
310     ObjectTypeInitializer.MaintainHandleCount = TRUE;
311     ObjectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
312     ObjectTypeInitializer.GenericMapping = IopFileMapping;
313     ObjectTypeInitializer.CloseProcedure = IopCloseFile;
314     ObjectTypeInitializer.DeleteProcedure = IopDeleteFile;
315     ObjectTypeInitializer.SecurityProcedure = IopGetSetSecurityObject;
316     ObjectTypeInitializer.QueryNameProcedure = IopQueryName;
317     ObjectTypeInitializer.ParseProcedure = IopParseFile;
318     ObjectTypeInitializer.UseDefaultObject = FALSE;
319     if (!NT_SUCCESS(ObCreateObjectType(&Name,
320                                        &ObjectTypeInitializer,
321                                        NULL,
322                                        &IoFileObjectType))) return FALSE;
323 
324     /* Success */
325     return TRUE;
326 }
327 
328 CODE_SEG("INIT")
329 BOOLEAN
330 NTAPI
331 IopCreateRootDirectories(VOID)
332 {
333     OBJECT_ATTRIBUTES ObjectAttributes;
334     UNICODE_STRING DirName;
335     HANDLE Handle;
336     NTSTATUS Status;
337 
338     /* Create the '\Driver' object directory */
339     RtlInitUnicodeString(&DirName, L"\\Driver");
340     InitializeObjectAttributes(&ObjectAttributes,
341                                &DirName,
342                                OBJ_PERMANENT,
343                                NULL,
344                                NULL);
345     Status = NtCreateDirectoryObject(&Handle,
346                                      DIRECTORY_ALL_ACCESS,
347                                      &ObjectAttributes);
348     if (!NT_SUCCESS(Status))
349     {
350         DPRINT1("Failed to create \\Driver directory: 0x%lx\n", Status);
351         return FALSE;
352     }
353     NtClose(Handle);
354 
355     /* Create the '\FileSystem' object directory */
356     RtlInitUnicodeString(&DirName, L"\\FileSystem");
357     InitializeObjectAttributes(&ObjectAttributes,
358                                &DirName,
359                                OBJ_PERMANENT,
360                                NULL,
361                                NULL);
362     Status = NtCreateDirectoryObject(&Handle,
363                                      DIRECTORY_ALL_ACCESS,
364                                      &ObjectAttributes);
365     if (!NT_SUCCESS(Status))
366     {
367         DPRINT1("Failed to create \\FileSystem directory: 0x%lx\n", Status);
368         return FALSE;
369     }
370     NtClose(Handle);
371 
372     /* Create the '\FileSystem' object directory */
373     RtlInitUnicodeString(&DirName, L"\\FileSystem\\Filters");
374     InitializeObjectAttributes(&ObjectAttributes,
375                                &DirName,
376                                OBJ_PERMANENT,
377                                NULL,
378                                NULL);
379     Status = NtCreateDirectoryObject(&Handle,
380                                      DIRECTORY_ALL_ACCESS,
381                                      &ObjectAttributes);
382     if (!NT_SUCCESS(Status))
383     {
384         DPRINT1("Failed to create \\FileSystem\\Filters directory: 0x%lx\n", Status);
385         return FALSE;
386     }
387     NtClose(Handle);
388 
389     /* Return success */
390     return TRUE;
391 }
392 
393 CODE_SEG("INIT")
394 BOOLEAN
395 NTAPI
396 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
397 {
398     OBJECT_ATTRIBUTES ObjectAttributes;
399     STRING DeviceString;
400     CHAR Buffer[256];
401     UNICODE_STRING DeviceName;
402     NTSTATUS Status;
403     HANDLE FileHandle;
404     IO_STATUS_BLOCK IoStatusBlock;
405     PFILE_OBJECT FileObject;
406 
407     /* Build the ARC device name */
408     sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
409     RtlInitAnsiString(&DeviceString, Buffer);
410     Status = RtlAnsiStringToUnicodeString(&DeviceName, &DeviceString, TRUE);
411     if (!NT_SUCCESS(Status)) return FALSE;
412 
413     /* Open it */
414     InitializeObjectAttributes(&ObjectAttributes,
415                                &DeviceName,
416                                OBJ_CASE_INSENSITIVE,
417                                NULL,
418                                NULL);
419     Status = ZwOpenFile(&FileHandle,
420                         FILE_READ_ATTRIBUTES,
421                         &ObjectAttributes,
422                         &IoStatusBlock,
423                         0,
424                         FILE_NON_DIRECTORY_FILE);
425     if (!NT_SUCCESS(Status))
426     {
427         /* Fail */
428         KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
429                      (ULONG_PTR)&DeviceName,
430                      Status,
431                      0,
432                      0);
433     }
434 
435     /* Get the DO */
436     Status = ObReferenceObjectByHandle(FileHandle,
437                                        0,
438                                        IoFileObjectType,
439                                        KernelMode,
440                                        (PVOID *)&FileObject,
441                                        NULL);
442     if (!NT_SUCCESS(Status))
443     {
444         /* Fail */
445         RtlFreeUnicodeString(&DeviceName);
446         return FALSE;
447     }
448 
449     /* Mark it as the boot partition */
450     FileObject->DeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
451 
452     /* Save a copy of the DO for the I/O Error Logger */
453     ObReferenceObject(FileObject->DeviceObject);
454     IopErrorLogObject = FileObject->DeviceObject;
455 
456     /* Cleanup and return success */
457     RtlFreeUnicodeString(&DeviceName);
458     NtClose(FileHandle);
459     ObDereferenceObject(FileObject);
460     return TRUE;
461 }
462 
463 CODE_SEG("INIT")
464 BOOLEAN
465 NTAPI
466 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
467 {
468     LARGE_INTEGER ExpireTime;
469     NTSTATUS Status;
470     CHAR Buffer[256];
471     ANSI_STRING NtBootPath, RootString;
472 
473     /* Initialize empty NT Boot Path */
474     RtlInitEmptyAnsiString(&NtBootPath, Buffer, sizeof(Buffer));
475 
476     /* Initialize the lookaside lists */
477     IopInitLookasideLists();
478 
479     /* Initialize all locks and lists */
480     ExInitializeResourceLite(&IopDatabaseResource);
481     ExInitializeResourceLite(&IopSecurityResource);
482     ExInitializeResourceLite(&IopDriverLoadResource);
483     InitializeListHead(&IopDiskFileSystemQueueHead);
484     InitializeListHead(&IopCdRomFileSystemQueueHead);
485     InitializeListHead(&IopTapeFileSystemQueueHead);
486     InitializeListHead(&IopNetworkFileSystemQueueHead);
487     InitializeListHead(&DriverBootReinitListHead);
488     InitializeListHead(&DriverReinitListHead);
489     InitializeListHead(&ShutdownListHead);
490     InitializeListHead(&LastChanceShutdownListHead);
491     InitializeListHead(&IopFsNotifyChangeQueueHead);
492     InitializeListHead(&IopErrorLogListHead);
493     KeInitializeSpinLock(&IoStatisticsLock);
494     KeInitializeSpinLock(&DriverReinitListLock);
495     KeInitializeSpinLock(&DriverBootReinitListLock);
496     KeInitializeSpinLock(&ShutdownListLock);
497     KeInitializeSpinLock(&IopLogListLock);
498 
499     /* Initialize PnP notifications */
500     PiInitializeNotifications();
501 
502     /* Initialize the reserve IRP */
503     if (!IopInitializeReserveIrp(&IopReserveIrpAllocator))
504     {
505         DPRINT1("IopInitializeReserveIrp failed!\n");
506         return FALSE;
507     }
508 
509     /* Initialize Timer List Lock */
510     KeInitializeSpinLock(&IopTimerLock);
511 
512     /* Initialize Timer List */
513     InitializeListHead(&IopTimerQueueHead);
514 
515     /* Initialize the DPC/Timer which will call the other Timer Routines */
516     ExpireTime.QuadPart = -10000000;
517     KeInitializeDpc(&IopTimerDpc, IopTimerDispatch, NULL);
518     KeInitializeTimerEx(&IopTimer, SynchronizationTimer);
519     KeSetTimerEx(&IopTimer, ExpireTime, 1000, &IopTimerDpc);
520 
521     /* Create Object Types */
522     if (!IopCreateObjectTypes())
523     {
524         DPRINT1("IopCreateObjectTypes failed!\n");
525         return FALSE;
526     }
527 
528     /* Create Object Directories */
529     if (!IopCreateRootDirectories())
530     {
531         DPRINT1("IopCreateRootDirectories failed!\n");
532         return FALSE;
533     }
534 
535     /* Initialize PnP manager */
536     IopInitializePlugPlayServices();
537 
538     /* Initialize SHIM engine */
539     ApphelpCacheInitialize();
540 
541     /* Initialize WMI */
542     WmiInitialize();
543 
544     /* Initialize HAL Root Bus Driver */
545     HalInitPnpDriver();
546 
547     /* Reenumerate what HAL has added (synchronously)
548      * This function call should eventually become a 2nd stage of the PnP initialization */
549     PiQueueDeviceAction(IopRootDeviceNode->PhysicalDeviceObject,
550                         PiActionEnumRootDevices,
551                         NULL,
552                         NULL);
553 
554     /* Make loader block available for the whole kernel */
555     IopLoaderBlock = LoaderBlock;
556 
557     /* Load boot start drivers */
558     IopInitializeBootDrivers();
559 
560     /* Call back drivers that asked for */
561     IopReinitializeBootDrivers();
562 
563     /* Check if this was a ramdisk boot */
564     if (!_strnicmp(LoaderBlock->ArcBootDeviceName, "ramdisk(0)", 10))
565     {
566         /* Initialize the ramdisk driver */
567         IopStartRamdisk(LoaderBlock);
568     }
569 
570     /* No one should need loader block any longer */
571     IopLoaderBlock = NULL;
572 
573     /* Create ARC names for boot devices */
574     Status = IopCreateArcNames(LoaderBlock);
575     if (!NT_SUCCESS(Status))
576     {
577         DPRINT1("IopCreateArcNames failed: %lx\n", Status);
578         return FALSE;
579     }
580 
581     /* Mark the system boot partition */
582     if (!IopMarkBootPartition(LoaderBlock))
583     {
584         DPRINT1("IopMarkBootPartition failed!\n");
585         return FALSE;
586     }
587 
588     /* The disk subsystem is initialized here and the SystemRoot is set too.
589      * We can finally load other drivers from the boot volume. */
590     PnPBootDriversInitialized = TRUE;
591 
592     /* Load system start drivers */
593     IopInitializeSystemDrivers();
594     PnpSystemInit = TRUE;
595 
596     /* Reinitialize drivers that requested it */
597     IopReinitializeDrivers();
598 
599     /* Convert SystemRoot from ARC to NT path */
600     Status = IopReassignSystemRoot(LoaderBlock, &NtBootPath);
601     if (!NT_SUCCESS(Status))
602     {
603         DPRINT1("IopReassignSystemRoot failed: %lx\n", Status);
604         return FALSE;
605     }
606 
607     /* Set the ANSI_STRING for the root path */
608     RootString.MaximumLength = NtSystemRoot.MaximumLength / sizeof(WCHAR);
609     RootString.Length = 0;
610     RootString.Buffer = ExAllocatePoolWithTag(PagedPool,
611                                               RootString.MaximumLength,
612                                               TAG_IO);
613 
614     /* Convert the path into the ANSI_STRING */
615     Status = RtlUnicodeStringToAnsiString(&RootString, &NtSystemRoot, FALSE);
616     if (!NT_SUCCESS(Status))
617     {
618         DPRINT1("RtlUnicodeStringToAnsiString failed: %lx\n", Status);
619         return FALSE;
620     }
621 
622     /* Assign drive letters */
623     IoAssignDriveLetters(LoaderBlock,
624                          &NtBootPath,
625                          (PUCHAR)RootString.Buffer,
626                          &RootString);
627 
628     /* Update system root */
629     Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &RootString, FALSE);
630     if (!NT_SUCCESS(Status))
631     {
632         DPRINT1("RtlAnsiStringToUnicodeString failed: %lx\n", Status);
633         return FALSE;
634     }
635 
636     /* Load the System DLL and its entrypoints */
637     Status = PsLocateSystemDll();
638     if (!NT_SUCCESS(Status))
639     {
640         DPRINT1("PsLocateSystemDll failed: %lx\n", Status);
641         return FALSE;
642     }
643 
644     /* Return success */
645     return TRUE;
646 }
647 
648 BOOLEAN
649 NTAPI
650 IoInitializeCrashDump(IN HANDLE PageFileHandle)
651 {
652     UNIMPLEMENTED;
653     return FALSE;
654 }
655 
656 /* EOF */
657