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