6fad94a2963cfde2998af1f46fc8aef075ea1a22
[reactos.git] / reactos / 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
43 GENERIC_MAPPING IopFileMapping = {
44 FILE_GENERIC_READ,
45 FILE_GENERIC_WRITE,
46 FILE_GENERIC_EXECUTE,
47 FILE_ALL_ACCESS};
48
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;
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 #if defined (ALLOC_PRAGMA)
84 #pragma alloc_text(INIT, IoInitSystem)
85 #endif
86
87 /* INIT FUNCTIONS ************************************************************/
88
89 VOID
90 INIT_FUNCTION
91 NTAPI
92 IopInitLookasideLists(VOID)
93 {
94 ULONG LargeIrpSize, SmallIrpSize, MdlSize;
95 LONG i;
96 PKPRCB Prcb;
97 PGENERAL_LOOKASIDE CurrentList = NULL;
98
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));
103
104 /* Initialize the Lookaside List for I\O Completion */
105 ExInitializeSystemLookasideList(&IoCompletionPacketLookaside,
106 NonPagedPool,
107 sizeof(IOP_MINI_COMPLETION_PACKET),
108 IOC_TAG1,
109 32,
110 &ExSystemLookasideListHead);
111
112 /* Initialize the Lookaside List for Large IRPs */
113 ExInitializeSystemLookasideList(&IoLargeIrpLookaside,
114 NonPagedPool,
115 LargeIrpSize,
116 IO_LARGEIRP,
117 64,
118 &ExSystemLookasideListHead);
119
120
121 /* Initialize the Lookaside List for Small IRPs */
122 ExInitializeSystemLookasideList(&IoSmallIrpLookaside,
123 NonPagedPool,
124 SmallIrpSize,
125 IO_SMALLIRP,
126 32,
127 &ExSystemLookasideListHead);
128
129 /* Initialize the Lookaside List for MDLs */
130 ExInitializeSystemLookasideList(&IopMdlLookasideList,
131 NonPagedPool,
132 MdlSize,
133 TAG_MDL,
134 128,
135 &ExSystemLookasideListHead);
136
137 /* Allocate the global lookaside list buffer */
138 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
139 4 * KeNumberProcessors *
140 sizeof(GENERAL_LOOKASIDE),
141 TAG_IO);
142
143 /* Loop all processors */
144 for (i = 0; i < KeNumberProcessors; i++)
145 {
146 /* Get the PRCB for this CPU */
147 Prcb = KiProcessorBlock[i];
148 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i, Prcb);
149
150 /* Write IRP credit limit */
151 Prcb->LookasideIrpFloat = 512 / KeNumberProcessors;
152
153 /* Set the I/O Completion List */
154 Prcb->PPLookasideList[LookasideCompletionList].L = &IoCompletionPacketLookaside;
155 if (CurrentList)
156 {
157 /* Initialize the Lookaside List for mini-packets */
158 ExInitializeSystemLookasideList(CurrentList,
159 NonPagedPool,
160 sizeof(IOP_MINI_COMPLETION_PACKET),
161 IO_SMALLIRP_CPU,
162 32,
163 &ExSystemLookasideListHead);
164 Prcb->PPLookasideList[LookasideCompletionList].P = CurrentList;
165 CurrentList++;
166
167 }
168 else
169 {
170 Prcb->PPLookasideList[LookasideCompletionList].P = &IoCompletionPacketLookaside;
171 }
172
173 /* Set the Large IRP List */
174 Prcb->PPLookasideList[LookasideLargeIrpList].L = &IoLargeIrpLookaside;
175 if (CurrentList)
176 {
177 /* Initialize the Lookaside List for Large IRPs */
178 ExInitializeSystemLookasideList(CurrentList,
179 NonPagedPool,
180 LargeIrpSize,
181 IO_LARGEIRP_CPU,
182 64,
183 &ExSystemLookasideListHead);
184 Prcb->PPLookasideList[LookasideLargeIrpList].P = CurrentList;
185 CurrentList++;
186
187 }
188 else
189 {
190 Prcb->PPLookasideList[LookasideLargeIrpList].P = &IoLargeIrpLookaside;
191 }
192
193 /* Set the Small IRP List */
194 Prcb->PPLookasideList[LookasideSmallIrpList].L = &IoSmallIrpLookaside;
195 if (CurrentList)
196 {
197 /* Initialize the Lookaside List for Small IRPs */
198 ExInitializeSystemLookasideList(CurrentList,
199 NonPagedPool,
200 SmallIrpSize,
201 IO_SMALLIRP_CPU,
202 32,
203 &ExSystemLookasideListHead);
204 Prcb->PPLookasideList[LookasideSmallIrpList].P = CurrentList;
205 CurrentList++;
206
207 }
208 else
209 {
210 Prcb->PPLookasideList[LookasideSmallIrpList].P = &IoSmallIrpLookaside;
211 }
212
213 /* Set the MDL Completion List */
214 Prcb->PPLookasideList[LookasideMdlList].L = &IopMdlLookasideList;
215 if (CurrentList)
216 {
217 /* Initialize the Lookaside List for MDLs */
218 ExInitializeSystemLookasideList(CurrentList,
219 NonPagedPool,
220 SmallIrpSize,
221 TAG_MDL,
222 128,
223 &ExSystemLookasideListHead);
224
225 Prcb->PPLookasideList[LookasideMdlList].P = CurrentList;
226 CurrentList++;
227
228 }
229 else
230 {
231 Prcb->PPLookasideList[LookasideMdlList].P = &IopMdlLookasideList;
232 }
233 }
234 }
235
236 BOOLEAN
237 INIT_FUNCTION
238 NTAPI
239 IopCreateObjectTypes(VOID)
240 {
241 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
242 UNICODE_STRING Name;
243
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;
252
253 /* Do the Adapter Type */
254 RtlInitUnicodeString(&Name, L"Adapter");
255 if (!NT_SUCCESS(ObCreateObjectType(&Name,
256 &ObjectTypeInitializer,
257 NULL,
258 &IoAdapterObjectType))) return FALSE;
259
260 /* Do the Controller Type */
261 RtlInitUnicodeString(&Name, L"Controller");
262 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CONTROLLER_OBJECT);
263 if (!NT_SUCCESS(ObCreateObjectType(&Name,
264 &ObjectTypeInitializer,
265 NULL,
266 &IoControllerObjectType))) return FALSE;
267
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,
276 NULL,
277 &IoDeviceObjectType))) return FALSE;
278
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,
287 NULL,
288 &IoDriverObjectType))) return FALSE;
289
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,
299 NULL,
300 &IoCompletionType))) return FALSE;
301
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,
317 NULL,
318 &IoFileObjectType))) return FALSE;
319
320 /* Success */
321 return TRUE;
322 }
323
324 BOOLEAN
325 INIT_FUNCTION
326 NTAPI
327 IopCreateRootDirectories()
328 {
329 OBJECT_ATTRIBUTES ObjectAttributes;
330 UNICODE_STRING DirName;
331 HANDLE Handle;
332
333 /* Create the '\Driver' object directory */
334 RtlInitUnicodeString(&DirName, L"\\Driver");
335 InitializeObjectAttributes(&ObjectAttributes,
336 &DirName,
337 OBJ_PERMANENT,
338 NULL,
339 NULL);
340 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
341 DIRECTORY_ALL_ACCESS,
342 &ObjectAttributes))) return FALSE;
343 NtClose(Handle);
344
345 /* Create the '\FileSystem' object directory */
346 RtlInitUnicodeString(&DirName, L"\\FileSystem");
347 InitializeObjectAttributes(&ObjectAttributes,
348 &DirName,
349 OBJ_PERMANENT,
350 NULL,
351 NULL);
352 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
353 DIRECTORY_ALL_ACCESS,
354 &ObjectAttributes))) return FALSE;
355 NtClose(Handle);
356
357 /* Return success */
358 return TRUE;
359 }
360
361 BOOLEAN
362 INIT_FUNCTION
363 NTAPI
364 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
365 {
366 OBJECT_ATTRIBUTES ObjectAttributes;
367 STRING DeviceString;
368 CHAR Buffer[256];
369 UNICODE_STRING DeviceName;
370 NTSTATUS Status;
371 HANDLE FileHandle;
372 IO_STATUS_BLOCK IoStatusBlock;
373 PFILE_OBJECT FileObject;
374
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;
380
381 /* Open it */
382 InitializeObjectAttributes(&ObjectAttributes,
383 &DeviceName,
384 OBJ_CASE_INSENSITIVE,
385 NULL,
386 NULL);
387 Status = ZwOpenFile(&FileHandle,
388 FILE_READ_ATTRIBUTES,
389 &ObjectAttributes,
390 &IoStatusBlock,
391 0,
392 FILE_NON_DIRECTORY_FILE);
393 if (!NT_SUCCESS(Status))
394 {
395 /* Fail */
396 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
397 (ULONG_PTR)&DeviceName,
398 Status,
399 0,
400 0);
401 }
402
403 /* Get the DO */
404 Status = ObReferenceObjectByHandle(FileHandle,
405 0,
406 IoFileObjectType,
407 KernelMode,
408 (PVOID *)&FileObject,
409 NULL);
410 if (!NT_SUCCESS(Status))
411 {
412 /* Fail */
413 RtlFreeUnicodeString(&DeviceName);
414 return FALSE;
415 }
416
417 /* Mark it as the boot partition */
418 FileObject->DeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
419
420 /* Save a copy of the DO for the I/O Error Logger */
421 ObReferenceObject(FileObject->DeviceObject);
422 IopErrorLogObject = FileObject->DeviceObject;
423
424 /* Cleanup and return success */
425 RtlFreeUnicodeString(&DeviceName);
426 NtClose(FileHandle);
427 ObDereferenceObject(FileObject);
428 return TRUE;
429 }
430
431 BOOLEAN
432 INIT_FUNCTION
433 NTAPI
434 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
435 {
436 LARGE_INTEGER ExpireTime;
437 NTSTATUS Status;
438 CHAR Buffer[256];
439 ANSI_STRING NtBootPath, RootString;
440
441 /* Initialize empty NT Boot Path */
442 RtlInitEmptyAnsiString(&NtBootPath, Buffer, sizeof(Buffer));
443
444 /* Initialize the lookaside lists */
445 IopInitLookasideLists();
446
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);
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()) return FALSE;
484
485 /* Create Object Directories */
486 if (!IopCreateRootDirectories()) return FALSE;
487
488 /* Initialize PnP manager */
489 PnpInit();
490
491 /* Create the group driver list */
492 IoCreateDriverList();
493
494 /* Load boot start drivers */
495 IopInitializeBootDrivers();
496
497 /* Call back drivers that asked for */
498 IopReinitializeBootDrivers();
499
500 /* Check if this was a ramdisk boot */
501 if (!_strnicmp(LoaderBlock->ArcBootDeviceName, "ramdisk(0)", 10))
502 {
503 /* Initialize the ramdisk driver */
504 IopStartRamdisk(LoaderBlock);
505 }
506
507 /* Create ARC names for boot devices */
508 IopCreateArcNames(LoaderBlock);
509
510 /* Mark the system boot partition */
511 if (!IopMarkBootPartition(LoaderBlock)) return FALSE;
512
513 /* Initialize PnP root relations */
514 IopEnumerateDevice(IopRootDeviceNode->PhysicalDeviceObject);
515
516 #ifndef _WINKD_
517 /* Read KDB Data */
518 KdbInit();
519
520 /* I/O is now setup for disk access, so phase 3 */
521 KdInitSystem(3, LoaderBlock);
522 #endif
523
524 /* Load services for devices found by PnP manager */
525 IopInitializePnpServices(IopRootDeviceNode);
526
527 /* Load system start drivers */
528 IopInitializeSystemDrivers();
529 PnpSystemInit = TRUE;
530
531 /* Destroy the group driver list */
532 IoDestroyDriverList();
533
534 /* Reinitialize drivers that requested it */
535 IopReinitializeDrivers();
536
537 /* Convert SystemRoot from ARC to NT path */
538 Status = IopReassignSystemRoot(LoaderBlock, &NtBootPath);
539 if (!NT_SUCCESS(Status)) return FALSE;
540
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,
546 TAG_IO);
547
548 /* Convert the path into the ANSI_STRING */
549 Status = RtlUnicodeStringToAnsiString(&RootString, &NtSystemRoot, FALSE);
550 if (!NT_SUCCESS(Status)) return FALSE;
551
552 /* Assign drive letters */
553 IoAssignDriveLetters(LoaderBlock,
554 &NtBootPath,
555 (PUCHAR)RootString.Buffer,
556 &RootString);
557
558 /* Update system root */
559 Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &RootString, FALSE);
560 if (!NT_SUCCESS(Status)) return FALSE;
561
562 /* Load the System DLL and its Entrypoints */
563 if (!NT_SUCCESS(PsLocateSystemDll())) return FALSE;
564
565 /* Return success */
566 return TRUE;
567 }
568
569 /* EOF */