[CLT2012]
[reactos.git] / ntoskrnl / io / iomgr / iomgr.c
1 /*
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
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 /* DATA ********************************************************************/
29
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];
44
45 GENERIC_MAPPING IopFileMapping = {
46 FILE_GENERIC_READ,
47 FILE_GENERIC_WRITE,
48 FILE_GENERIC_EXECUTE,
49 FILE_ALL_ACCESS};
50
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 KGUARDED_MUTEX PnpNotifyListLock;
58 extern LIST_ENTRY IopDiskFileSystemQueueHead;
59 extern LIST_ENTRY IopCdRomFileSystemQueueHead;
60 extern LIST_ENTRY IopTapeFileSystemQueueHead;
61 extern LIST_ENTRY IopNetworkFileSystemQueueHead;
62 extern LIST_ENTRY DriverBootReinitListHead;
63 extern LIST_ENTRY DriverReinitListHead;
64 extern LIST_ENTRY PnpNotifyListHead;
65 extern LIST_ENTRY IopFsNotifyChangeQueueHead;
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;
75
76 extern PDEVICE_OBJECT IopErrorLogObject;
77
78 GENERAL_LOOKASIDE IoLargeIrpLookaside;
79 GENERAL_LOOKASIDE IoSmallIrpLookaside;
80 GENERAL_LOOKASIDE IopMdlLookasideList;
81 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside;
82
83 PLOADER_PARAMETER_BLOCK IopLoaderBlock;
84
85 #if defined (ALLOC_PRAGMA)
86 #pragma alloc_text(INIT, IoInitSystem)
87 #endif
88
89 /* INIT FUNCTIONS ************************************************************/
90
91 VOID
92 INIT_FUNCTION
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 BOOLEAN
239 INIT_FUNCTION
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 = IopSecurityFile;
276 if (!NT_SUCCESS(ObCreateObjectType(&Name,
277 &ObjectTypeInitializer,
278 NULL,
279 &IoDeviceObjectType))) return FALSE;
280
281 /* Initialize the Driver object type */
282 RtlInitUnicodeString(&Name, L"Driver");
283 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DRIVER_OBJECT);
284 ObjectTypeInitializer.DeleteProcedure = IopDeleteDriver;
285 ObjectTypeInitializer.ParseProcedure = NULL;
286 ObjectTypeInitializer.SecurityProcedure = NULL;
287 if (!NT_SUCCESS(ObCreateObjectType(&Name,
288 &ObjectTypeInitializer,
289 NULL,
290 &IoDriverObjectType))) return FALSE;
291
292 /* Initialize the I/O Completion object type */
293 RtlInitUnicodeString(&Name, L"IoCompletion");
294 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KQUEUE);
295 ObjectTypeInitializer.ValidAccessMask = IO_COMPLETION_ALL_ACCESS;
296 ObjectTypeInitializer.InvalidAttributes |= OBJ_PERMANENT;
297 ObjectTypeInitializer.GenericMapping = IopCompletionMapping;
298 ObjectTypeInitializer.DeleteProcedure = IopDeleteIoCompletion;
299 if (!NT_SUCCESS(ObCreateObjectType(&Name,
300 &ObjectTypeInitializer,
301 NULL,
302 &IoCompletionType))) return FALSE;
303
304 /* Initialize the File object type */
305 RtlInitUnicodeString(&Name, L"File");
306 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(FILE_OBJECT);
307 ObjectTypeInitializer.InvalidAttributes |= OBJ_EXCLUSIVE;
308 ObjectTypeInitializer.MaintainHandleCount = TRUE;
309 ObjectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
310 ObjectTypeInitializer.GenericMapping = IopFileMapping;
311 ObjectTypeInitializer.CloseProcedure = IopCloseFile;
312 ObjectTypeInitializer.DeleteProcedure = IopDeleteFile;
313 ObjectTypeInitializer.SecurityProcedure = IopSecurityFile;
314 ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile;
315 ObjectTypeInitializer.ParseProcedure = IopParseFile;
316 ObjectTypeInitializer.UseDefaultObject = FALSE;
317 if (!NT_SUCCESS(ObCreateObjectType(&Name,
318 &ObjectTypeInitializer,
319 NULL,
320 &IoFileObjectType))) return FALSE;
321
322 /* Success */
323 return TRUE;
324 }
325
326 BOOLEAN
327 INIT_FUNCTION
328 NTAPI
329 IopCreateRootDirectories()
330 {
331 OBJECT_ATTRIBUTES ObjectAttributes;
332 UNICODE_STRING DirName;
333 HANDLE Handle;
334
335 /* Create the '\Driver' object directory */
336 RtlInitUnicodeString(&DirName, L"\\Driver");
337 InitializeObjectAttributes(&ObjectAttributes,
338 &DirName,
339 OBJ_PERMANENT,
340 NULL,
341 NULL);
342 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
343 DIRECTORY_ALL_ACCESS,
344 &ObjectAttributes))) return FALSE;
345 NtClose(Handle);
346
347 /* Create the '\FileSystem' object directory */
348 RtlInitUnicodeString(&DirName, L"\\FileSystem");
349 InitializeObjectAttributes(&ObjectAttributes,
350 &DirName,
351 OBJ_PERMANENT,
352 NULL,
353 NULL);
354 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
355 DIRECTORY_ALL_ACCESS,
356 &ObjectAttributes))) return FALSE;
357 NtClose(Handle);
358
359 /* Return success */
360 return TRUE;
361 }
362
363 BOOLEAN
364 INIT_FUNCTION
365 NTAPI
366 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
367 {
368 OBJECT_ATTRIBUTES ObjectAttributes;
369 STRING DeviceString;
370 CHAR Buffer[256];
371 UNICODE_STRING DeviceName;
372 NTSTATUS Status;
373 HANDLE FileHandle;
374 IO_STATUS_BLOCK IoStatusBlock;
375 PFILE_OBJECT FileObject;
376
377 /* Build the ARC device name */
378 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
379 RtlInitAnsiString(&DeviceString, Buffer);
380 Status = RtlAnsiStringToUnicodeString(&DeviceName, &DeviceString, TRUE);
381 if (!NT_SUCCESS(Status)) return FALSE;
382
383 /* Open it */
384 InitializeObjectAttributes(&ObjectAttributes,
385 &DeviceName,
386 OBJ_CASE_INSENSITIVE,
387 NULL,
388 NULL);
389 Status = ZwOpenFile(&FileHandle,
390 FILE_READ_ATTRIBUTES,
391 &ObjectAttributes,
392 &IoStatusBlock,
393 0,
394 FILE_NON_DIRECTORY_FILE);
395 if (!NT_SUCCESS(Status))
396 {
397 /* Fail */
398 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
399 (ULONG_PTR)&DeviceName,
400 Status,
401 0,
402 0);
403 }
404
405 /* Get the DO */
406 Status = ObReferenceObjectByHandle(FileHandle,
407 0,
408 IoFileObjectType,
409 KernelMode,
410 (PVOID *)&FileObject,
411 NULL);
412 if (!NT_SUCCESS(Status))
413 {
414 /* Fail */
415 RtlFreeUnicodeString(&DeviceName);
416 return FALSE;
417 }
418
419 /* Mark it as the boot partition */
420 FileObject->DeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
421
422 /* Save a copy of the DO for the I/O Error Logger */
423 ObReferenceObject(FileObject->DeviceObject);
424 IopErrorLogObject = FileObject->DeviceObject;
425
426 /* Cleanup and return success */
427 RtlFreeUnicodeString(&DeviceName);
428 NtClose(FileHandle);
429 ObDereferenceObject(FileObject);
430 return TRUE;
431 }
432
433 BOOLEAN
434 INIT_FUNCTION
435 NTAPI
436 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
437 {
438 LARGE_INTEGER ExpireTime;
439 NTSTATUS Status;
440 CHAR Buffer[256];
441 ANSI_STRING NtBootPath, RootString;
442
443 /* Initialize empty NT Boot Path */
444 RtlInitEmptyAnsiString(&NtBootPath, Buffer, sizeof(Buffer));
445
446 /* Initialize the lookaside lists */
447 IopInitLookasideLists();
448
449 /* Initialize all locks and lists */
450 ExInitializeResource(&IopDatabaseResource);
451 ExInitializeResource(&IopSecurityResource);
452 KeInitializeGuardedMutex(&PnpNotifyListLock);
453 InitializeListHead(&IopDiskFileSystemQueueHead);
454 InitializeListHead(&IopCdRomFileSystemQueueHead);
455 InitializeListHead(&IopTapeFileSystemQueueHead);
456 InitializeListHead(&IopNetworkFileSystemQueueHead);
457 InitializeListHead(&DriverBootReinitListHead);
458 InitializeListHead(&DriverReinitListHead);
459 InitializeListHead(&PnpNotifyListHead);
460 InitializeListHead(&ShutdownListHead);
461 InitializeListHead(&LastChanceShutdownListHead);
462 InitializeListHead(&IopFsNotifyChangeQueueHead);
463 InitializeListHead(&IopErrorLogListHead);
464 KeInitializeSpinLock(&IoStatisticsLock);
465 KeInitializeSpinLock(&DriverReinitListLock);
466 KeInitializeSpinLock(&DriverBootReinitListLock);
467 KeInitializeSpinLock(&ShutdownListLock);
468 KeInitializeSpinLock(&IopLogListLock);
469
470 /* Initialize Timer List Lock */
471 KeInitializeSpinLock(&IopTimerLock);
472
473 /* Initialize Timer List */
474 InitializeListHead(&IopTimerQueueHead);
475
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);
481
482 /* Create Object Types */
483 if (!IopCreateObjectTypes())
484 {
485 DPRINT1("IopCreateObjectTypes failed!\n");
486 return FALSE;
487 }
488
489 /* Create Object Directories */
490 if (!IopCreateRootDirectories())
491 {
492 DPRINT1("IopCreateRootDirectories failed!\n");
493 return FALSE;
494 }
495
496 /* Initialize PnP manager */
497 IopInitializePlugPlayServices();
498
499 /* Initialize HAL Root Bus Driver */
500 HalInitPnpDriver();
501
502 /* Make loader block available for the whole kernel */
503 IopLoaderBlock = LoaderBlock;
504
505 /* Load boot start drivers */
506 IopInitializeBootDrivers();
507
508 /* Call back drivers that asked for */
509 IopReinitializeBootDrivers();
510
511 /* Check if this was a ramdisk boot */
512 if (!_strnicmp(LoaderBlock->ArcBootDeviceName, "ramdisk(0)", 10))
513 {
514 /* Initialize the ramdisk driver */
515 IopStartRamdisk(LoaderBlock);
516 }
517
518 /* No one should need loader block any longer */
519 IopLoaderBlock = NULL;
520
521 /* Create ARC names for boot devices */
522 Status = IopCreateArcNames(LoaderBlock);
523 if (!NT_SUCCESS(Status))
524 {
525 DPRINT1("IopCreateArcNames failed: %lx\n", Status);
526 return FALSE;
527 }
528
529 /* Mark the system boot partition */
530 if (!IopMarkBootPartition(LoaderBlock))
531 {
532 DPRINT1("IopMarkBootPartition failed!\n");
533 return FALSE;
534 }
535
536 /* Initialize PnP root relations */
537 IopEnumerateDevice(IopRootDeviceNode->PhysicalDeviceObject);
538
539 #ifndef _WINKD_
540 /* Read KDB Data */
541 KdbInit();
542
543 /* I/O is now setup for disk access, so phase 3 */
544 KdInitSystem(3, LoaderBlock);
545 #endif
546
547 /* Load services for devices found by PnP manager */
548 IopInitializePnpServices(IopRootDeviceNode);
549
550 /* Load system start drivers */
551 IopInitializeSystemDrivers();
552 PnpSystemInit = TRUE;
553
554 /* Reinitialize drivers that requested it */
555 IopReinitializeDrivers();
556
557 /* Convert SystemRoot from ARC to NT path */
558 Status = IopReassignSystemRoot(LoaderBlock, &NtBootPath);
559 if (!NT_SUCCESS(Status))
560 {
561 DPRINT1("IopReassignSystemRoot failed: %lx\n", Status);
562 return FALSE;
563 }
564
565 /* Set the ANSI_STRING for the root path */
566 RootString.MaximumLength = NtSystemRoot.MaximumLength / sizeof(WCHAR);
567 RootString.Length = 0;
568 RootString.Buffer = ExAllocatePoolWithTag(PagedPool,
569 RootString.MaximumLength,
570 TAG_IO);
571
572 /* Convert the path into the ANSI_STRING */
573 Status = RtlUnicodeStringToAnsiString(&RootString, &NtSystemRoot, FALSE);
574 if (!NT_SUCCESS(Status))
575 {
576 DPRINT1("RtlUnicodeStringToAnsiString failed: %lx\n", Status);
577 return FALSE;
578 }
579
580 /* Assign drive letters */
581 IoAssignDriveLetters(LoaderBlock,
582 &NtBootPath,
583 (PUCHAR)RootString.Buffer,
584 &RootString);
585
586 /* Update system root */
587 Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &RootString, FALSE);
588 if (!NT_SUCCESS(Status))
589 {
590 DPRINT1("RtlAnsiStringToUnicodeString failed: %lx\n", Status);
591 return FALSE;
592 }
593
594 /* Load the System DLL and its Entrypoints */
595 Status = PsLocateSystemDll();
596 if (!NT_SUCCESS(Status))
597 {
598 DPRINT1("PsLocateSystemDll failed: %lx\n", Status);
599 return FALSE;
600 }
601
602 /* Return success */
603 return TRUE;
604 }
605
606 /* EOF */