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
33 /* DATA ********************************************************************/
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];
49 GENERIC_MAPPING IopFileMapping
= {
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
;
81 extern PDEVICE_OBJECT IopErrorLogObject
;
83 GENERAL_LOOKASIDE IoLargeIrpLookaside
;
84 GENERAL_LOOKASIDE IoSmallIrpLookaside
;
85 GENERAL_LOOKASIDE IopMdlLookasideList
;
86 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside
;
88 PLOADER_PARAMETER_BLOCK IopLoaderBlock
;
90 #if defined (ALLOC_PRAGMA)
91 #pragma alloc_text(INIT, IoInitSystem)
94 /* INIT FUNCTIONS ************************************************************/
99 IopInitLookasideLists(VOID
)
101 ULONG LargeIrpSize
, SmallIrpSize
, MdlSize
;
104 PGENERAL_LOOKASIDE CurrentList
= NULL
;
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
));
111 /* Initialize the Lookaside List for I\O Completion */
112 ExInitializeSystemLookasideList(&IoCompletionPacketLookaside
,
114 sizeof(IOP_MINI_COMPLETION_PACKET
),
117 &ExSystemLookasideListHead
);
119 /* Initialize the Lookaside List for Large IRPs */
120 ExInitializeSystemLookasideList(&IoLargeIrpLookaside
,
125 &ExSystemLookasideListHead
);
128 /* Initialize the Lookaside List for Small IRPs */
129 ExInitializeSystemLookasideList(&IoSmallIrpLookaside
,
134 &ExSystemLookasideListHead
);
136 /* Initialize the Lookaside List for MDLs */
137 ExInitializeSystemLookasideList(&IopMdlLookasideList
,
142 &ExSystemLookasideListHead
);
144 /* Allocate the global lookaside list buffer */
145 CurrentList
= ExAllocatePoolWithTag(NonPagedPool
,
146 4 * KeNumberProcessors
*
147 sizeof(GENERAL_LOOKASIDE
),
150 /* Loop all processors */
151 for (i
= 0; i
< KeNumberProcessors
; i
++)
153 /* Get the PRCB for this CPU */
154 Prcb
= KiProcessorBlock
[i
];
155 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i
, Prcb
);
157 /* Write IRP credit limit */
158 Prcb
->LookasideIrpFloat
= 512 / KeNumberProcessors
;
160 /* Set the I/O Completion List */
161 Prcb
->PPLookasideList
[LookasideCompletionList
].L
= &IoCompletionPacketLookaside
;
164 /* Initialize the Lookaside List for mini-packets */
165 ExInitializeSystemLookasideList(CurrentList
,
167 sizeof(IOP_MINI_COMPLETION_PACKET
),
170 &ExSystemLookasideListHead
);
171 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= CurrentList
;
177 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= &IoCompletionPacketLookaside
;
180 /* Set the Large IRP List */
181 Prcb
->PPLookasideList
[LookasideLargeIrpList
].L
= &IoLargeIrpLookaside
;
184 /* Initialize the Lookaside List for Large IRPs */
185 ExInitializeSystemLookasideList(CurrentList
,
190 &ExSystemLookasideListHead
);
191 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= CurrentList
;
197 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= &IoLargeIrpLookaside
;
200 /* Set the Small IRP List */
201 Prcb
->PPLookasideList
[LookasideSmallIrpList
].L
= &IoSmallIrpLookaside
;
204 /* Initialize the Lookaside List for Small IRPs */
205 ExInitializeSystemLookasideList(CurrentList
,
210 &ExSystemLookasideListHead
);
211 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= CurrentList
;
217 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= &IoSmallIrpLookaside
;
220 /* Set the MDL Completion List */
221 Prcb
->PPLookasideList
[LookasideMdlList
].L
= &IopMdlLookasideList
;
224 /* Initialize the Lookaside List for MDLs */
225 ExInitializeSystemLookasideList(CurrentList
,
230 &ExSystemLookasideListHead
);
232 Prcb
->PPLookasideList
[LookasideMdlList
].P
= CurrentList
;
238 Prcb
->PPLookasideList
[LookasideMdlList
].P
= &IopMdlLookasideList
;
246 IopCreateObjectTypes(VOID
)
248 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
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
;
260 /* Do the Adapter Type */
261 RtlInitUnicodeString(&Name
, L
"Adapter");
262 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
263 &ObjectTypeInitializer
,
265 &IoAdapterObjectType
))) return FALSE
;
267 /* Do the Controller Type */
268 RtlInitUnicodeString(&Name
, L
"Controller");
269 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CONTROLLER_OBJECT
);
270 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
271 &ObjectTypeInitializer
,
273 &IoControllerObjectType
))) return FALSE
;
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
,
285 &IoDeviceObjectType
))) return FALSE
;
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
,
296 &IoDriverObjectType
))) return FALSE
;
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
,
308 &IoCompletionType
))) return FALSE
;
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
,
326 &IoFileObjectType
))) return FALSE
;
335 IopCreateRootDirectories(VOID
)
337 OBJECT_ATTRIBUTES ObjectAttributes
;
338 UNICODE_STRING DirName
;
342 /* Create the '\Driver' object directory */
343 RtlInitUnicodeString(&DirName
, L
"\\Driver");
344 InitializeObjectAttributes(&ObjectAttributes
,
349 Status
= NtCreateDirectoryObject(&Handle
,
350 DIRECTORY_ALL_ACCESS
,
352 if (!NT_SUCCESS(Status
))
354 DPRINT1("Failed to create \\Driver directory: 0x%lx\n", Status
);
359 /* Create the '\FileSystem' object directory */
360 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
361 InitializeObjectAttributes(&ObjectAttributes
,
366 Status
= NtCreateDirectoryObject(&Handle
,
367 DIRECTORY_ALL_ACCESS
,
369 if (!NT_SUCCESS(Status
))
371 DPRINT1("Failed to create \\FileSystem directory: 0x%lx\n", Status
);
376 /* Create the '\FileSystem' object directory */
377 RtlInitUnicodeString(&DirName
, L
"\\FileSystem\\Filters");
378 InitializeObjectAttributes(&ObjectAttributes
,
383 Status
= NtCreateDirectoryObject(&Handle
,
384 DIRECTORY_ALL_ACCESS
,
386 if (!NT_SUCCESS(Status
))
388 DPRINT1("Failed to create \\FileSystem\\Filters directory: 0x%lx\n", Status
);
400 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
402 OBJECT_ATTRIBUTES ObjectAttributes
;
405 UNICODE_STRING DeviceName
;
408 IO_STATUS_BLOCK IoStatusBlock
;
409 PFILE_OBJECT FileObject
;
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
;
418 InitializeObjectAttributes(&ObjectAttributes
,
420 OBJ_CASE_INSENSITIVE
,
423 Status
= ZwOpenFile(&FileHandle
,
424 FILE_READ_ATTRIBUTES
,
428 FILE_NON_DIRECTORY_FILE
);
429 if (!NT_SUCCESS(Status
))
432 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
433 (ULONG_PTR
)&DeviceName
,
440 Status
= ObReferenceObjectByHandle(FileHandle
,
444 (PVOID
*)&FileObject
,
446 if (!NT_SUCCESS(Status
))
449 RtlFreeUnicodeString(&DeviceName
);
453 /* Mark it as the boot partition */
454 FileObject
->DeviceObject
->Flags
|= DO_SYSTEM_BOOT_PARTITION
;
456 /* Save a copy of the DO for the I/O Error Logger */
457 ObReferenceObject(FileObject
->DeviceObject
);
458 IopErrorLogObject
= FileObject
->DeviceObject
;
460 /* Cleanup and return success */
461 RtlFreeUnicodeString(&DeviceName
);
463 ObDereferenceObject(FileObject
);
470 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
472 LARGE_INTEGER ExpireTime
;
475 ANSI_STRING NtBootPath
, RootString
;
477 /* Initialize empty NT Boot Path */
478 RtlInitEmptyAnsiString(&NtBootPath
, Buffer
, sizeof(Buffer
));
480 /* Initialize the lookaside lists */
481 IopInitLookasideLists();
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
);
505 /* Initialize Timer List Lock */
506 KeInitializeSpinLock(&IopTimerLock
);
508 /* Initialize Timer List */
509 InitializeListHead(&IopTimerQueueHead
);
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
);
517 /* Create Object Types */
518 if (!IopCreateObjectTypes())
520 DPRINT1("IopCreateObjectTypes failed!\n");
524 /* Create Object Directories */
525 if (!IopCreateRootDirectories())
527 DPRINT1("IopCreateRootDirectories failed!\n");
531 /* Initialize PnP manager */
532 IopInitializePlugPlayServices();
534 /* Initialize SHIM engine */
535 ApphelpCacheInitialize();
540 /* Initialize HAL Root Bus Driver */
543 /* Make loader block available for the whole kernel */
544 IopLoaderBlock
= LoaderBlock
;
546 /* Load boot start drivers */
547 IopInitializeBootDrivers();
549 /* Call back drivers that asked for */
550 IopReinitializeBootDrivers();
552 /* Check if this was a ramdisk boot */
553 if (!_strnicmp(LoaderBlock
->ArcBootDeviceName
, "ramdisk(0)", 10))
555 /* Initialize the ramdisk driver */
556 IopStartRamdisk(LoaderBlock
);
559 /* No one should need loader block any longer */
560 IopLoaderBlock
= NULL
;
562 /* Create ARC names for boot devices */
563 Status
= IopCreateArcNames(LoaderBlock
);
564 if (!NT_SUCCESS(Status
))
566 DPRINT1("IopCreateArcNames failed: %lx\n", Status
);
570 /* Mark the system boot partition */
571 if (!IopMarkBootPartition(LoaderBlock
))
573 DPRINT1("IopMarkBootPartition failed!\n");
577 /* Initialize PnP root relations */
578 IopEnumerateDevice(IopRootDeviceNode
->PhysicalDeviceObject
);
584 /* I/O is now setup for disk access, so phase 3 */
585 KdInitSystem(3, LoaderBlock
);
588 /* Load services for devices found by PnP manager */
589 IopInitializePnpServices(IopRootDeviceNode
);
591 /* Load system start drivers */
592 IopInitializeSystemDrivers();
593 PnpSystemInit
= TRUE
;
595 /* Reinitialize drivers that requested it */
596 IopReinitializeDrivers();
598 /* Convert SystemRoot from ARC to NT path */
599 Status
= IopReassignSystemRoot(LoaderBlock
, &NtBootPath
);
600 if (!NT_SUCCESS(Status
))
602 DPRINT1("IopReassignSystemRoot failed: %lx\n", Status
);
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
,
613 /* Convert the path into the ANSI_STRING */
614 Status
= RtlUnicodeStringToAnsiString(&RootString
, &NtSystemRoot
, FALSE
);
615 if (!NT_SUCCESS(Status
))
617 DPRINT1("RtlUnicodeStringToAnsiString failed: %lx\n", Status
);
621 /* Assign drive letters */
622 IoAssignDriveLetters(LoaderBlock
,
624 (PUCHAR
)RootString
.Buffer
,
627 /* Update system root */
628 Status
= RtlAnsiStringToUnicodeString(&NtSystemRoot
, &RootString
, FALSE
);
629 if (!NT_SUCCESS(Status
))
631 DPRINT1("RtlAnsiStringToUnicodeString failed: %lx\n", Status
);
635 /* Load the System DLL and its Entrypoints */
636 Status
= PsLocateSystemDll();
637 if (!NT_SUCCESS(Status
))
639 DPRINT1("PsLocateSystemDll failed: %lx\n", Status
);