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;
43 GENERIC_MAPPING IopFileMapping
= {
49 extern LIST_ENTRY ShutdownListHead
;
50 extern LIST_ENTRY LastChanceShutdownListHead
;
51 extern KSPIN_LOCK ShutdownListLock
;
52 extern POBJECT_TYPE IoAdapterObjectType
;
53 ERESOURCE IopDatabaseResource
;
54 extern ERESOURCE FileSystemListLock
;
55 ERESOURCE IopSecurityResource
;
56 extern KGUARDED_MUTEX FsChangeNotifyListLock
;
57 extern KGUARDED_MUTEX PnpNotifyListLock
;
58 extern LIST_ENTRY IopDiskFsListHead
;
59 extern LIST_ENTRY IopCdRomFsListHead
;
60 extern LIST_ENTRY IopTapeFsListHead
;
61 extern LIST_ENTRY IopNetworkFsListHead
;
62 extern LIST_ENTRY DriverBootReinitListHead
;
63 extern LIST_ENTRY DriverReinitListHead
;
64 extern LIST_ENTRY PnpNotifyListHead
;
65 extern LIST_ENTRY FsChangeNotifyListHead
;
66 extern LIST_ENTRY IopErrorLogListHead
;
67 extern LIST_ENTRY IopTimerQueueHead
;
68 extern KDPC IopTimerDpc
;
69 extern KTIMER IopTimer
;
70 extern KSPIN_LOCK IoStatisticsLock
;
71 extern KSPIN_LOCK DriverReinitListLock
;
72 extern KSPIN_LOCK DriverBootReinitListLock
;
73 extern KSPIN_LOCK IopLogListLock
;
74 extern KSPIN_LOCK IopTimerLock
;
76 extern PDEVICE_OBJECT IopErrorLogObject
;
78 GENERAL_LOOKASIDE IoLargeIrpLookaside
;
79 GENERAL_LOOKASIDE IoSmallIrpLookaside
;
80 GENERAL_LOOKASIDE IopMdlLookasideList
;
81 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside
;
83 #if defined (ALLOC_PRAGMA)
84 #pragma alloc_text(INIT, IoInitSystem)
87 /* INIT FUNCTIONS ************************************************************/
92 IopInitLookasideLists(VOID
)
94 ULONG LargeIrpSize
, SmallIrpSize
, MdlSize
;
97 PGENERAL_LOOKASIDE CurrentList
= NULL
;
99 /* Calculate the sizes */
100 LargeIrpSize
= sizeof(IRP
) + (8 * sizeof(IO_STACK_LOCATION
));
101 SmallIrpSize
= sizeof(IRP
) + sizeof(IO_STACK_LOCATION
);
102 MdlSize
= sizeof(MDL
) + (23 * sizeof(PFN_NUMBER
));
104 /* Initialize the Lookaside List for I\O Completion */
105 ExInitializeSystemLookasideList(&IoCompletionPacketLookaside
,
107 sizeof(IOP_MINI_COMPLETION_PACKET
),
110 &ExSystemLookasideListHead
);
112 /* Initialize the Lookaside List for Large IRPs */
113 ExInitializeSystemLookasideList(&IoLargeIrpLookaside
,
118 &ExSystemLookasideListHead
);
121 /* Initialize the Lookaside List for Small IRPs */
122 ExInitializeSystemLookasideList(&IoSmallIrpLookaside
,
127 &ExSystemLookasideListHead
);
129 /* Initialize the Lookaside List for MDLs */
130 ExInitializeSystemLookasideList(&IopMdlLookasideList
,
135 &ExSystemLookasideListHead
);
137 /* Allocate the global lookaside list buffer */
138 CurrentList
= ExAllocatePoolWithTag(NonPagedPool
,
139 4 * KeNumberProcessors
*
140 sizeof(GENERAL_LOOKASIDE
),
143 /* Loop all processors */
144 for (i
= 0; i
< KeNumberProcessors
; i
++)
146 /* Get the PRCB for this CPU */
147 Prcb
= KiProcessorBlock
[i
];
148 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i
, Prcb
);
150 /* Write IRP credit limit */
151 Prcb
->LookasideIrpFloat
= 512 / KeNumberProcessors
;
153 /* Set the I/O Completion List */
154 Prcb
->PPLookasideList
[LookasideCompletionList
].L
= &IoCompletionPacketLookaside
;
157 /* Initialize the Lookaside List for mini-packets */
158 ExInitializeSystemLookasideList(CurrentList
,
160 sizeof(IOP_MINI_COMPLETION_PACKET
),
163 &ExSystemLookasideListHead
);
164 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= CurrentList
;
170 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= &IoCompletionPacketLookaside
;
173 /* Set the Large IRP List */
174 Prcb
->PPLookasideList
[LookasideLargeIrpList
].L
= &IoLargeIrpLookaside
;
177 /* Initialize the Lookaside List for Large IRPs */
178 ExInitializeSystemLookasideList(CurrentList
,
183 &ExSystemLookasideListHead
);
184 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= CurrentList
;
190 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= &IoLargeIrpLookaside
;
193 /* Set the Small IRP List */
194 Prcb
->PPLookasideList
[LookasideSmallIrpList
].L
= &IoSmallIrpLookaside
;
197 /* Initialize the Lookaside List for Small IRPs */
198 ExInitializeSystemLookasideList(CurrentList
,
203 &ExSystemLookasideListHead
);
204 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= CurrentList
;
210 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= &IoSmallIrpLookaside
;
213 /* Set the MDL Completion List */
214 Prcb
->PPLookasideList
[LookasideMdlList
].L
= &IopMdlLookasideList
;
217 /* Initialize the Lookaside List for MDLs */
218 ExInitializeSystemLookasideList(CurrentList
,
223 &ExSystemLookasideListHead
);
225 Prcb
->PPLookasideList
[LookasideMdlList
].P
= CurrentList
;
231 Prcb
->PPLookasideList
[LookasideMdlList
].P
= &IopMdlLookasideList
;
239 IopCreateObjectTypes(VOID
)
241 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
244 /* Initialize default settings */
245 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
246 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
247 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
248 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
249 ObjectTypeInitializer
.ValidAccessMask
= FILE_ALL_ACCESS
;
250 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
251 ObjectTypeInitializer
.GenericMapping
= IopFileMapping
;
253 /* Do the Adapter Type */
254 RtlInitUnicodeString(&Name
, L
"Adapter");
255 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
256 &ObjectTypeInitializer
,
258 &IoAdapterObjectType
))) return FALSE
;
260 /* Do the Controller Type */
261 RtlInitUnicodeString(&Name
, L
"Controller");
262 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CONTROLLER_OBJECT
);
263 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
264 &ObjectTypeInitializer
,
266 &IoControllerObjectType
))) return FALSE
;
268 /* Do the Device Type */
269 RtlInitUnicodeString(&Name
, L
"Device");
270 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DEVICE_OBJECT
);
271 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDevice
;
272 ObjectTypeInitializer
.ParseProcedure
= IopParseDevice
;
273 ObjectTypeInitializer
.SecurityProcedure
= IopSecurityFile
;
274 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
275 &ObjectTypeInitializer
,
277 &IoDeviceObjectType
))) return FALSE
;
279 /* Initialize the Driver object type */
280 RtlInitUnicodeString(&Name
, L
"Driver");
281 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DRIVER_OBJECT
);
282 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDriver
;
283 ObjectTypeInitializer
.ParseProcedure
= NULL
;
284 ObjectTypeInitializer
.SecurityProcedure
= NULL
;
285 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
286 &ObjectTypeInitializer
,
288 &IoDriverObjectType
))) return FALSE
;
290 /* Initialize the I/O Completion object type */
291 RtlInitUnicodeString(&Name
, L
"IoCompletion");
292 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KQUEUE
);
293 ObjectTypeInitializer
.ValidAccessMask
= IO_COMPLETION_ALL_ACCESS
;
294 ObjectTypeInitializer
.InvalidAttributes
|= OBJ_PERMANENT
;
295 ObjectTypeInitializer
.GenericMapping
= IopCompletionMapping
;
296 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteIoCompletion
;
297 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
298 &ObjectTypeInitializer
,
300 &IoCompletionType
))) return FALSE
;
302 /* Initialize the File object type */
303 RtlInitUnicodeString(&Name
, L
"File");
304 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(FILE_OBJECT
);
305 ObjectTypeInitializer
.InvalidAttributes
|= OBJ_EXCLUSIVE
;
306 ObjectTypeInitializer
.MaintainHandleCount
= TRUE
;
307 ObjectTypeInitializer
.ValidAccessMask
= FILE_ALL_ACCESS
;
308 ObjectTypeInitializer
.GenericMapping
= IopFileMapping
;
309 ObjectTypeInitializer
.CloseProcedure
= IopCloseFile
;
310 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteFile
;
311 ObjectTypeInitializer
.SecurityProcedure
= IopSecurityFile
;
312 ObjectTypeInitializer
.QueryNameProcedure
= IopQueryNameFile
;
313 ObjectTypeInitializer
.ParseProcedure
= IopParseFile
;
314 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
315 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
316 &ObjectTypeInitializer
,
318 &IoFileObjectType
))) return FALSE
;
327 IopCreateRootDirectories()
329 OBJECT_ATTRIBUTES ObjectAttributes
;
330 UNICODE_STRING DirName
;
333 /* Create the '\Driver' object directory */
334 RtlInitUnicodeString(&DirName
, L
"\\Driver");
335 InitializeObjectAttributes(&ObjectAttributes
,
340 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle
,
341 DIRECTORY_ALL_ACCESS
,
342 &ObjectAttributes
))) return FALSE
;
345 /* Create the '\FileSystem' object directory */
346 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
347 InitializeObjectAttributes(&ObjectAttributes
,
352 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle
,
353 DIRECTORY_ALL_ACCESS
,
354 &ObjectAttributes
))) return FALSE
;
364 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
366 OBJECT_ATTRIBUTES ObjectAttributes
;
369 UNICODE_STRING DeviceName
;
372 IO_STATUS_BLOCK IoStatusBlock
;
373 PFILE_OBJECT FileObject
;
375 /* Build the ARC device name */
376 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
377 RtlInitAnsiString(&DeviceString
, Buffer
);
378 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &DeviceString
, TRUE
);
379 if (!NT_SUCCESS(Status
)) return FALSE
;
382 InitializeObjectAttributes(&ObjectAttributes
,
384 OBJ_CASE_INSENSITIVE
,
387 Status
= ZwOpenFile(&FileHandle
,
388 FILE_READ_ATTRIBUTES
,
392 FILE_NON_DIRECTORY_FILE
);
393 if (!NT_SUCCESS(Status
))
396 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
397 (ULONG_PTR
)&DeviceName
,
404 Status
= ObReferenceObjectByHandle(FileHandle
,
408 (PVOID
*)&FileObject
,
410 if (!NT_SUCCESS(Status
))
413 RtlFreeUnicodeString(&DeviceName
);
417 /* Mark it as the boot partition */
418 FileObject
->DeviceObject
->Flags
|= DO_SYSTEM_BOOT_PARTITION
;
420 /* Save a copy of the DO for the I/O Error Logger */
421 ObReferenceObject(FileObject
->DeviceObject
);
422 IopErrorLogObject
= FileObject
->DeviceObject
;
424 /* Cleanup and return success */
425 RtlFreeUnicodeString(&DeviceName
);
427 ObDereferenceObject(FileObject
);
434 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
436 LARGE_INTEGER ExpireTime
;
439 ANSI_STRING NtBootPath
, RootString
;
441 /* Initialize empty NT Boot Path */
442 RtlInitEmptyAnsiString(&NtBootPath
, Buffer
, sizeof(Buffer
));
444 /* Initialize the lookaside lists */
445 IopInitLookasideLists();
447 /* Initialize all locks and lists */
448 ExInitializeResource(&IopDatabaseResource
);
449 ExInitializeResource(&FileSystemListLock
);
450 ExInitializeResource(&IopSecurityResource
);
451 KeInitializeGuardedMutex(&FsChangeNotifyListLock
);
452 KeInitializeGuardedMutex(&PnpNotifyListLock
);
453 InitializeListHead(&IopDiskFsListHead
);
454 InitializeListHead(&IopCdRomFsListHead
);
455 InitializeListHead(&IopTapeFsListHead
);
456 InitializeListHead(&IopNetworkFsListHead
);
457 InitializeListHead(&DriverBootReinitListHead
);
458 InitializeListHead(&DriverReinitListHead
);
459 InitializeListHead(&PnpNotifyListHead
);
460 InitializeListHead(&ShutdownListHead
);
461 InitializeListHead(&LastChanceShutdownListHead
);
462 InitializeListHead(&FsChangeNotifyListHead
);
463 InitializeListHead(&IopErrorLogListHead
);
464 KeInitializeSpinLock(&IoStatisticsLock
);
465 KeInitializeSpinLock(&DriverReinitListLock
);
466 KeInitializeSpinLock(&DriverBootReinitListLock
);
467 KeInitializeSpinLock(&ShutdownListLock
);
468 KeInitializeSpinLock(&IopLogListLock
);
470 /* Initialize Timer List Lock */
471 KeInitializeSpinLock(&IopTimerLock
);
473 /* Initialize Timer List */
474 InitializeListHead(&IopTimerQueueHead
);
476 /* Initialize the DPC/Timer which will call the other Timer Routines */
477 ExpireTime
.QuadPart
= -10000000;
478 KeInitializeDpc(&IopTimerDpc
, IopTimerDispatch
, NULL
);
479 KeInitializeTimerEx(&IopTimer
, SynchronizationTimer
);
480 KeSetTimerEx(&IopTimer
, ExpireTime
, 1000, &IopTimerDpc
);
482 /* Create Object Types */
483 if (!IopCreateObjectTypes()) return FALSE
;
485 /* Create Object Directories */
486 if (!IopCreateRootDirectories()) return FALSE
;
488 /* Initialize PnP manager */
491 /* Create the group driver list */
492 IoCreateDriverList();
494 /* Load boot start drivers */
495 IopInitializeBootDrivers();
497 /* Call back drivers that asked for */
498 IopReinitializeBootDrivers();
500 /* Check if this was a ramdisk boot */
501 if (!_strnicmp(LoaderBlock
->ArcBootDeviceName
, "ramdisk(0)", 10))
503 /* Initialize the ramdisk driver */
504 IopStartRamdisk(LoaderBlock
);
507 /* Create ARC names for boot devices */
508 IopCreateArcNames(LoaderBlock
);
510 /* Mark the system boot partition */
511 if (!IopMarkBootPartition(LoaderBlock
)) return FALSE
;
513 /* Initialize PnP root relations */
514 IopEnumerateDevice(IopRootDeviceNode
->PhysicalDeviceObject
);
520 /* I/O is now setup for disk access, so phase 3 */
521 KdInitSystem(3, LoaderBlock
);
524 /* Load services for devices found by PnP manager */
525 IopInitializePnpServices(IopRootDeviceNode
);
527 /* Load system start drivers */
528 IopInitializeSystemDrivers();
529 PnpSystemInit
= TRUE
;
531 /* Destroy the group driver list */
532 IoDestroyDriverList();
534 /* Reinitialize drivers that requested it */
535 IopReinitializeDrivers();
537 /* Convert SystemRoot from ARC to NT path */
538 Status
= IopReassignSystemRoot(LoaderBlock
, &NtBootPath
);
539 if (!NT_SUCCESS(Status
)) return FALSE
;
541 /* Set the ANSI_STRING for the root path */
542 RootString
.MaximumLength
= NtSystemRoot
.MaximumLength
/ sizeof(WCHAR
);
543 RootString
.Length
= 0;
544 RootString
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
545 RootString
.MaximumLength
,
548 /* Convert the path into the ANSI_STRING */
549 Status
= RtlUnicodeStringToAnsiString(&RootString
, &NtSystemRoot
, FALSE
);
550 if (!NT_SUCCESS(Status
)) return FALSE
;
552 /* Assign drive letters */
553 IoAssignDriveLetters(LoaderBlock
,
555 (PUCHAR
)RootString
.Buffer
,
558 /* Update system root */
559 Status
= RtlAnsiStringToUnicodeString(&NtSystemRoot
, &RootString
, FALSE
);
560 if (!NT_SUCCESS(Status
)) return FALSE
;
562 /* Load the System DLL and its Entrypoints */
563 if (!NT_SUCCESS(PsLocateSystemDll())) return FALSE
;