2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/io/iomgr.c
5 * PURPOSE: I/O Manager Initialization and Misc Utility Functions
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
10 /* INCLUDES ****************************************************************/
16 ULONG IopTraceLevel
= 0;
17 BOOLEAN PnpSystemInit
= FALSE
;
23 IN PVOID DeferredContext
,
24 IN PVOID SystemArgument1
,
25 IN PVOID SystemArgument2
28 /* DATA ********************************************************************/
30 POBJECT_TYPE IoDeviceObjectType
= NULL
;
31 POBJECT_TYPE IoFileObjectType
= NULL
;
32 extern POBJECT_TYPE IoControllerObjectType
;
33 extern UNICODE_STRING NtSystemRoot
;
34 BOOLEAN IoCountOperations
= TRUE
;
35 ULONG IoReadOperationCount
= 0;
36 LARGE_INTEGER IoReadTransferCount
= {{0, 0}};
37 ULONG IoWriteOperationCount
= 0;
38 LARGE_INTEGER IoWriteTransferCount
= {{0, 0}};
39 ULONG IoOtherOperationCount
= 0;
40 LARGE_INTEGER IoOtherTransferCount
= {{0, 0}};
41 KSPIN_LOCK IoStatisticsLock
= 0;
42 ULONG IopNumTriageDumpDataBlocks
;
43 PVOID IopTriageDumpDataBlocks
[64];
45 GENERIC_MAPPING IopFileMapping
= {
51 extern LIST_ENTRY ShutdownListHead
;
52 extern LIST_ENTRY LastChanceShutdownListHead
;
53 extern KSPIN_LOCK ShutdownListLock
;
54 extern POBJECT_TYPE IoAdapterObjectType
;
55 extern ERESOURCE IopDatabaseResource
;
56 ERESOURCE IopSecurityResource
;
57 extern ERESOURCE IopDriverLoadResource
;
58 extern KGUARDED_MUTEX PnpNotifyListLock
;
59 extern LIST_ENTRY IopDiskFileSystemQueueHead
;
60 extern LIST_ENTRY IopCdRomFileSystemQueueHead
;
61 extern LIST_ENTRY IopTapeFileSystemQueueHead
;
62 extern LIST_ENTRY IopNetworkFileSystemQueueHead
;
63 extern LIST_ENTRY DriverBootReinitListHead
;
64 extern LIST_ENTRY DriverReinitListHead
;
65 extern LIST_ENTRY PnpNotifyListHead
;
66 extern LIST_ENTRY IopFsNotifyChangeQueueHead
;
67 extern LIST_ENTRY IopErrorLogListHead
;
68 extern LIST_ENTRY IopTimerQueueHead
;
69 extern KDPC IopTimerDpc
;
70 extern KTIMER IopTimer
;
71 extern KSPIN_LOCK IoStatisticsLock
;
72 extern KSPIN_LOCK DriverReinitListLock
;
73 extern KSPIN_LOCK DriverBootReinitListLock
;
74 extern KSPIN_LOCK IopLogListLock
;
75 extern KSPIN_LOCK IopTimerLock
;
77 extern PDEVICE_OBJECT IopErrorLogObject
;
79 GENERAL_LOOKASIDE IoLargeIrpLookaside
;
80 GENERAL_LOOKASIDE IoSmallIrpLookaside
;
81 GENERAL_LOOKASIDE IopMdlLookasideList
;
82 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside
;
84 PLOADER_PARAMETER_BLOCK IopLoaderBlock
;
86 #if defined (ALLOC_PRAGMA)
87 #pragma alloc_text(INIT, IoInitSystem)
90 /* INIT FUNCTIONS ************************************************************/
95 IopInitLookasideLists(VOID
)
97 ULONG LargeIrpSize
, SmallIrpSize
, MdlSize
;
100 PGENERAL_LOOKASIDE CurrentList
= NULL
;
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
));
107 /* Initialize the Lookaside List for I\O Completion */
108 ExInitializeSystemLookasideList(&IoCompletionPacketLookaside
,
110 sizeof(IOP_MINI_COMPLETION_PACKET
),
113 &ExSystemLookasideListHead
);
115 /* Initialize the Lookaside List for Large IRPs */
116 ExInitializeSystemLookasideList(&IoLargeIrpLookaside
,
121 &ExSystemLookasideListHead
);
124 /* Initialize the Lookaside List for Small IRPs */
125 ExInitializeSystemLookasideList(&IoSmallIrpLookaside
,
130 &ExSystemLookasideListHead
);
132 /* Initialize the Lookaside List for MDLs */
133 ExInitializeSystemLookasideList(&IopMdlLookasideList
,
138 &ExSystemLookasideListHead
);
140 /* Allocate the global lookaside list buffer */
141 CurrentList
= ExAllocatePoolWithTag(NonPagedPool
,
142 4 * KeNumberProcessors
*
143 sizeof(GENERAL_LOOKASIDE
),
146 /* Loop all processors */
147 for (i
= 0; i
< KeNumberProcessors
; i
++)
149 /* Get the PRCB for this CPU */
150 Prcb
= KiProcessorBlock
[i
];
151 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i
, Prcb
);
153 /* Write IRP credit limit */
154 Prcb
->LookasideIrpFloat
= 512 / KeNumberProcessors
;
156 /* Set the I/O Completion List */
157 Prcb
->PPLookasideList
[LookasideCompletionList
].L
= &IoCompletionPacketLookaside
;
160 /* Initialize the Lookaside List for mini-packets */
161 ExInitializeSystemLookasideList(CurrentList
,
163 sizeof(IOP_MINI_COMPLETION_PACKET
),
166 &ExSystemLookasideListHead
);
167 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= CurrentList
;
173 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= &IoCompletionPacketLookaside
;
176 /* Set the Large IRP List */
177 Prcb
->PPLookasideList
[LookasideLargeIrpList
].L
= &IoLargeIrpLookaside
;
180 /* Initialize the Lookaside List for Large IRPs */
181 ExInitializeSystemLookasideList(CurrentList
,
186 &ExSystemLookasideListHead
);
187 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= CurrentList
;
193 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= &IoLargeIrpLookaside
;
196 /* Set the Small IRP List */
197 Prcb
->PPLookasideList
[LookasideSmallIrpList
].L
= &IoSmallIrpLookaside
;
200 /* Initialize the Lookaside List for Small IRPs */
201 ExInitializeSystemLookasideList(CurrentList
,
206 &ExSystemLookasideListHead
);
207 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= CurrentList
;
213 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= &IoSmallIrpLookaside
;
216 /* Set the MDL Completion List */
217 Prcb
->PPLookasideList
[LookasideMdlList
].L
= &IopMdlLookasideList
;
220 /* Initialize the Lookaside List for MDLs */
221 ExInitializeSystemLookasideList(CurrentList
,
226 &ExSystemLookasideListHead
);
228 Prcb
->PPLookasideList
[LookasideMdlList
].P
= CurrentList
;
234 Prcb
->PPLookasideList
[LookasideMdlList
].P
= &IopMdlLookasideList
;
242 IopCreateObjectTypes(VOID
)
244 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
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
;
256 /* Do the Adapter Type */
257 RtlInitUnicodeString(&Name
, L
"Adapter");
258 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
259 &ObjectTypeInitializer
,
261 &IoAdapterObjectType
))) return FALSE
;
263 /* Do the Controller Type */
264 RtlInitUnicodeString(&Name
, L
"Controller");
265 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CONTROLLER_OBJECT
);
266 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
267 &ObjectTypeInitializer
,
269 &IoControllerObjectType
))) return FALSE
;
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
= IopSecurityFile
;
277 ObjectTypeInitializer
.CaseInsensitive
= TRUE
;
278 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
279 &ObjectTypeInitializer
,
281 &IoDeviceObjectType
))) return FALSE
;
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
,
292 &IoDriverObjectType
))) return FALSE
;
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
,
304 &IoCompletionType
))) return FALSE
;
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
= IopSecurityFile
;
316 ObjectTypeInitializer
.QueryNameProcedure
= IopQueryNameFile
;
317 ObjectTypeInitializer
.ParseProcedure
= IopParseFile
;
318 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
319 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
320 &ObjectTypeInitializer
,
322 &IoFileObjectType
))) return FALSE
;
331 IopCreateRootDirectories()
333 OBJECT_ATTRIBUTES ObjectAttributes
;
334 UNICODE_STRING DirName
;
338 /* Create the '\Driver' object directory */
339 RtlInitUnicodeString(&DirName
, L
"\\Driver");
340 InitializeObjectAttributes(&ObjectAttributes
,
345 Status
= NtCreateDirectoryObject(&Handle
,
346 DIRECTORY_ALL_ACCESS
,
348 if (!NT_SUCCESS(Status
))
350 DPRINT1("Failed to create \\Driver directory: 0x%lx\n", Status
);
355 /* Create the '\FileSystem' object directory */
356 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
357 InitializeObjectAttributes(&ObjectAttributes
,
362 Status
= NtCreateDirectoryObject(&Handle
,
363 DIRECTORY_ALL_ACCESS
,
365 if (!NT_SUCCESS(Status
))
367 DPRINT1("Failed to create \\FileSystem directory: 0x%lx\n", Status
);
372 /* Create the '\FileSystem' object directory */
373 RtlInitUnicodeString(&DirName
, L
"\\FileSystem\\Filters");
374 InitializeObjectAttributes(&ObjectAttributes
,
379 Status
= NtCreateDirectoryObject(&Handle
,
380 DIRECTORY_ALL_ACCESS
,
382 if (!NT_SUCCESS(Status
))
384 DPRINT1("Failed to create \\FileSystem\\Filters directory: 0x%lx\n", Status
);
396 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
398 OBJECT_ATTRIBUTES ObjectAttributes
;
401 UNICODE_STRING DeviceName
;
404 IO_STATUS_BLOCK IoStatusBlock
;
405 PFILE_OBJECT FileObject
;
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
;
414 InitializeObjectAttributes(&ObjectAttributes
,
416 OBJ_CASE_INSENSITIVE
,
419 Status
= ZwOpenFile(&FileHandle
,
420 FILE_READ_ATTRIBUTES
,
424 FILE_NON_DIRECTORY_FILE
);
425 if (!NT_SUCCESS(Status
))
428 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
429 (ULONG_PTR
)&DeviceName
,
436 Status
= ObReferenceObjectByHandle(FileHandle
,
440 (PVOID
*)&FileObject
,
442 if (!NT_SUCCESS(Status
))
445 RtlFreeUnicodeString(&DeviceName
);
449 /* Mark it as the boot partition */
450 FileObject
->DeviceObject
->Flags
|= DO_SYSTEM_BOOT_PARTITION
;
452 /* Save a copy of the DO for the I/O Error Logger */
453 ObReferenceObject(FileObject
->DeviceObject
);
454 IopErrorLogObject
= FileObject
->DeviceObject
;
456 /* Cleanup and return success */
457 RtlFreeUnicodeString(&DeviceName
);
459 ObDereferenceObject(FileObject
);
466 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
468 LARGE_INTEGER ExpireTime
;
471 ANSI_STRING NtBootPath
, RootString
;
473 /* Initialize empty NT Boot Path */
474 RtlInitEmptyAnsiString(&NtBootPath
, Buffer
, sizeof(Buffer
));
476 /* Initialize the lookaside lists */
477 IopInitLookasideLists();
479 /* Initialize all locks and lists */
480 ExInitializeResourceLite(&IopDatabaseResource
);
481 ExInitializeResourceLite(&IopSecurityResource
);
482 ExInitializeResourceLite(&IopDriverLoadResource
);
483 KeInitializeGuardedMutex(&PnpNotifyListLock
);
484 InitializeListHead(&IopDiskFileSystemQueueHead
);
485 InitializeListHead(&IopCdRomFileSystemQueueHead
);
486 InitializeListHead(&IopTapeFileSystemQueueHead
);
487 InitializeListHead(&IopNetworkFileSystemQueueHead
);
488 InitializeListHead(&DriverBootReinitListHead
);
489 InitializeListHead(&DriverReinitListHead
);
490 InitializeListHead(&PnpNotifyListHead
);
491 InitializeListHead(&ShutdownListHead
);
492 InitializeListHead(&LastChanceShutdownListHead
);
493 InitializeListHead(&IopFsNotifyChangeQueueHead
);
494 InitializeListHead(&IopErrorLogListHead
);
495 KeInitializeSpinLock(&IoStatisticsLock
);
496 KeInitializeSpinLock(&DriverReinitListLock
);
497 KeInitializeSpinLock(&DriverBootReinitListLock
);
498 KeInitializeSpinLock(&ShutdownListLock
);
499 KeInitializeSpinLock(&IopLogListLock
);
501 /* Initialize Timer List Lock */
502 KeInitializeSpinLock(&IopTimerLock
);
504 /* Initialize Timer List */
505 InitializeListHead(&IopTimerQueueHead
);
507 /* Initialize the DPC/Timer which will call the other Timer Routines */
508 ExpireTime
.QuadPart
= -10000000;
509 KeInitializeDpc(&IopTimerDpc
, IopTimerDispatch
, NULL
);
510 KeInitializeTimerEx(&IopTimer
, SynchronizationTimer
);
511 KeSetTimerEx(&IopTimer
, ExpireTime
, 1000, &IopTimerDpc
);
513 /* Create Object Types */
514 if (!IopCreateObjectTypes())
516 DPRINT1("IopCreateObjectTypes failed!\n");
520 /* Create Object Directories */
521 if (!IopCreateRootDirectories())
523 DPRINT1("IopCreateRootDirectories failed!\n");
527 /* Initialize PnP manager */
528 IopInitializePlugPlayServices();
530 /* Initialize HAL Root Bus Driver */
533 /* Make loader block available for the whole kernel */
534 IopLoaderBlock
= LoaderBlock
;
536 /* Load boot start drivers */
537 IopInitializeBootDrivers();
539 /* Call back drivers that asked for */
540 IopReinitializeBootDrivers();
542 /* Check if this was a ramdisk boot */
543 if (!_strnicmp(LoaderBlock
->ArcBootDeviceName
, "ramdisk(0)", 10))
545 /* Initialize the ramdisk driver */
546 IopStartRamdisk(LoaderBlock
);
549 /* No one should need loader block any longer */
550 IopLoaderBlock
= NULL
;
552 /* Create ARC names for boot devices */
553 Status
= IopCreateArcNames(LoaderBlock
);
554 if (!NT_SUCCESS(Status
))
556 DPRINT1("IopCreateArcNames failed: %lx\n", Status
);
560 /* Mark the system boot partition */
561 if (!IopMarkBootPartition(LoaderBlock
))
563 DPRINT1("IopMarkBootPartition failed!\n");
567 /* Initialize PnP root relations */
568 IopEnumerateDevice(IopRootDeviceNode
->PhysicalDeviceObject
);
574 /* I/O is now setup for disk access, so phase 3 */
575 KdInitSystem(3, LoaderBlock
);
578 /* Load services for devices found by PnP manager */
579 IopInitializePnpServices(IopRootDeviceNode
);
581 /* Load system start drivers */
582 IopInitializeSystemDrivers();
583 PnpSystemInit
= TRUE
;
585 /* Reinitialize drivers that requested it */
586 IopReinitializeDrivers();
588 /* Convert SystemRoot from ARC to NT path */
589 Status
= IopReassignSystemRoot(LoaderBlock
, &NtBootPath
);
590 if (!NT_SUCCESS(Status
))
592 DPRINT1("IopReassignSystemRoot failed: %lx\n", Status
);
596 /* Set the ANSI_STRING for the root path */
597 RootString
.MaximumLength
= NtSystemRoot
.MaximumLength
/ sizeof(WCHAR
);
598 RootString
.Length
= 0;
599 RootString
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
600 RootString
.MaximumLength
,
603 /* Convert the path into the ANSI_STRING */
604 Status
= RtlUnicodeStringToAnsiString(&RootString
, &NtSystemRoot
, FALSE
);
605 if (!NT_SUCCESS(Status
))
607 DPRINT1("RtlUnicodeStringToAnsiString failed: %lx\n", Status
);
611 /* Assign drive letters */
612 IoAssignDriveLetters(LoaderBlock
,
614 (PUCHAR
)RootString
.Buffer
,
617 /* Update system root */
618 Status
= RtlAnsiStringToUnicodeString(&NtSystemRoot
, &RootString
, FALSE
);
619 if (!NT_SUCCESS(Status
))
621 DPRINT1("RtlAnsiStringToUnicodeString failed: %lx\n", Status
);
625 /* Load the System DLL and its Entrypoints */
626 Status
= PsLocateSystemDll();
627 if (!NT_SUCCESS(Status
))
629 DPRINT1("PsLocateSystemDll failed: %lx\n", Status
);