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