- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[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 <internal/debug.h>
15
16 ULONG IopTraceLevel = 0; //IO_API_DEBUG | IO_FILE_DEBUG;
17
18 // should go into a proper header
19 VOID
20 NTAPI
21 IoSynchronousInvalidateDeviceRelations(
22 IN PDEVICE_OBJECT DeviceObject,
23 IN DEVICE_RELATION_TYPE Type
24 );
25
26 VOID
27 NTAPI
28 IopTimerDispatch(
29 IN PKDPC Dpc,
30 IN PVOID DeferredContext,
31 IN PVOID SystemArgument1,
32 IN PVOID SystemArgument2
33 );
34
35 /* DATA ********************************************************************/
36
37 POBJECT_TYPE IoDeviceObjectType = NULL;
38 POBJECT_TYPE IoFileObjectType = NULL;
39 extern POBJECT_TYPE IoControllerObjectType;
40 extern UNICODE_STRING NtSystemRoot;
41 BOOLEAN IoCountOperations;
42 ULONG IoReadOperationCount = 0;
43 LARGE_INTEGER IoReadTransferCount = {{0, 0}};
44 ULONG IoWriteOperationCount = 0;
45 LARGE_INTEGER IoWriteTransferCount = {{0, 0}};
46 ULONG IoOtherOperationCount = 0;
47 LARGE_INTEGER IoOtherTransferCount = {{0, 0}};
48 KSPIN_LOCK IoStatisticsLock = 0;
49
50 GENERIC_MAPPING IopFileMapping = {
51 FILE_GENERIC_READ,
52 FILE_GENERIC_WRITE,
53 FILE_GENERIC_EXECUTE,
54 FILE_ALL_ACCESS};
55
56 extern LIST_ENTRY ShutdownListHead;
57 extern KSPIN_LOCK ShutdownListLock;
58 extern NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
59 extern POBJECT_TYPE IoAdapterObjectType;
60 ERESOURCE IopDatabaseResource;
61 extern ERESOURCE FileSystemListLock;
62 ERESOURCE IopSecurityResource;
63 extern KGUARDED_MUTEX FsChangeNotifyListLock;
64 extern KGUARDED_MUTEX PnpNotifyListLock;
65 extern LIST_ENTRY IopDiskFsListHead;
66 extern LIST_ENTRY IopCdRomFsListHead;
67 extern LIST_ENTRY IopTapeFsListHead;
68 extern LIST_ENTRY IopNetworkFsListHead;
69 extern LIST_ENTRY DriverBootReinitListHead;
70 extern LIST_ENTRY DriverReinitListHead;
71 extern LIST_ENTRY PnpNotifyListHead;
72 extern LIST_ENTRY FsChangeNotifyListHead;
73 extern LIST_ENTRY IopErrorLogListHead;
74 extern LIST_ENTRY IopTimerQueueHead;
75 extern KDPC IopTimerDpc;
76 extern KTIMER IopTimer;
77 extern KSPIN_LOCK CancelSpinLock;
78 extern KSPIN_LOCK IoVpbLock;
79 extern KSPIN_LOCK IoStatisticsLock;
80 extern KSPIN_LOCK DriverReinitListLock;
81 extern KSPIN_LOCK DriverBootReinitListLock;
82 extern KSPIN_LOCK IopLogListLock;
83 extern KSPIN_LOCK IopTimerLock;
84
85 extern PDEVICE_OBJECT IopErrorLogObject;
86
87 NPAGED_LOOKASIDE_LIST IoLargeIrpLookaside;
88 NPAGED_LOOKASIDE_LIST IoSmallIrpLookaside;
89 NPAGED_LOOKASIDE_LIST IopMdlLookasideList;
90
91 #if defined (ALLOC_PRAGMA)
92 #pragma alloc_text(INIT, IoInitSystem)
93 #endif
94
95 /* INIT FUNCTIONS ************************************************************/
96
97 VOID
98 INIT_FUNCTION
99 NTAPI
100 IopInitLookasideLists(VOID)
101 {
102 ULONG LargeIrpSize, SmallIrpSize, MdlSize;
103 LONG i;
104 PKPRCB Prcb;
105 PNPAGED_LOOKASIDE_LIST CurrentList = NULL;
106
107 /* Calculate the sizes */
108 LargeIrpSize = sizeof(IRP) + (8 * sizeof(IO_STACK_LOCATION));
109 SmallIrpSize = sizeof(IRP) + sizeof(IO_STACK_LOCATION);
110 MdlSize = sizeof(MDL) + (23 * sizeof(PFN_NUMBER));
111
112 /* Initialize the Lookaside List for Large IRPs */
113 ExInitializeNPagedLookasideList(&IoLargeIrpLookaside,
114 NULL,
115 NULL,
116 0,
117 LargeIrpSize,
118 IO_LARGEIRP,
119 64);
120
121 /* Initialize the Lookaside List for Small IRPs */
122 ExInitializeNPagedLookasideList(&IoSmallIrpLookaside,
123 NULL,
124 NULL,
125 0,
126 SmallIrpSize,
127 IO_SMALLIRP,
128 32);
129
130 /* Initialize the Lookaside List for I\O Completion */
131 ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
132 NULL,
133 NULL,
134 0,
135 sizeof(IO_COMPLETION_PACKET),
136 IOC_TAG1,
137 32);
138
139 /* Initialize the Lookaside List for MDLs */
140 ExInitializeNPagedLookasideList(&IopMdlLookasideList,
141 NULL,
142 NULL,
143 0,
144 MdlSize,
145 TAG_MDL,
146 128);
147
148 /* Now allocate the per-processor lists */
149 for (i = 0; i < KeNumberProcessors; i++)
150 {
151 /* Get the PRCB for this CPU */
152 Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
153 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i, Prcb);
154
155 /* Set the Large IRP List */
156 Prcb->PPLookasideList[LookasideLargeIrpList].L = &IoLargeIrpLookaside.L;
157 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
158 sizeof(NPAGED_LOOKASIDE_LIST),
159 IO_LARGEIRP_CPU);
160 if (CurrentList)
161 {
162 /* Initialize the Lookaside List for Large IRPs */
163 ExInitializeNPagedLookasideList(CurrentList,
164 NULL,
165 NULL,
166 0,
167 LargeIrpSize,
168 IO_LARGEIRP_CPU,
169 64);
170 }
171 else
172 {
173 CurrentList = &IoLargeIrpLookaside;
174 }
175 Prcb->PPLookasideList[LookasideLargeIrpList].P = &CurrentList->L;
176
177 /* Set the Small IRP List */
178 Prcb->PPLookasideList[LookasideSmallIrpList].L = &IoSmallIrpLookaside.L;
179 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
180 sizeof(NPAGED_LOOKASIDE_LIST),
181 IO_SMALLIRP_CPU);
182 if (CurrentList)
183 {
184 /* Initialize the Lookaside List for Small IRPs */
185 ExInitializeNPagedLookasideList(CurrentList,
186 NULL,
187 NULL,
188 0,
189 SmallIrpSize,
190 IO_SMALLIRP_CPU,
191 32);
192 }
193 else
194 {
195 CurrentList = &IoSmallIrpLookaside;
196 }
197 Prcb->PPLookasideList[LookasideSmallIrpList].P = &CurrentList->L;
198
199 /* Set the I/O Completion List */
200 Prcb->PPLookasideList[LookasideCompletionList].L = &IoCompletionPacketLookaside.L;
201 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
202 sizeof(NPAGED_LOOKASIDE_LIST),
203 IO_SMALLIRP_CPU);
204 if (CurrentList)
205 {
206 /* Initialize the Lookaside List for Large IRPs */
207 ExInitializeNPagedLookasideList(CurrentList,
208 NULL,
209 NULL,
210 0,
211 sizeof(IO_COMPLETION_PACKET),
212 IO_SMALLIRP_CPU,
213 32);
214 }
215 else
216 {
217 CurrentList = &IoCompletionPacketLookaside;
218 }
219 Prcb->PPLookasideList[LookasideCompletionList].P = &CurrentList->L;
220
221 /* Set the MDL Completion List */
222 Prcb->PPLookasideList[LookasideMdlList].L = &IopMdlLookasideList.L;
223 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
224 sizeof(NPAGED_LOOKASIDE_LIST),
225 TAG_MDL);
226 if (CurrentList)
227 {
228 /* Initialize the Lookaside List for MDLs */
229 ExInitializeNPagedLookasideList(CurrentList,
230 NULL,
231 NULL,
232 0,
233 SmallIrpSize,
234 TAG_MDL,
235 128);
236 }
237 else
238 {
239 CurrentList = &IopMdlLookasideList;
240 }
241 Prcb->PPLookasideList[LookasideMdlList].P = &CurrentList->L;
242 }
243 }
244
245 BOOLEAN
246 INIT_FUNCTION
247 NTAPI
248 IopCreateObjectTypes(VOID)
249 {
250 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
251 UNICODE_STRING Name;
252
253 /* Initialize default settings */
254 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
255 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
256 ObjectTypeInitializer.PoolType = NonPagedPool;
257 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
258 ObjectTypeInitializer.ValidAccessMask = FILE_ALL_ACCESS;
259 ObjectTypeInitializer.UseDefaultObject = TRUE;
260 ObjectTypeInitializer.GenericMapping = IopFileMapping;
261
262 /* Do the Adapter Type */
263 RtlInitUnicodeString(&Name, L"Adapter");
264 if (!NT_SUCCESS(ObCreateObjectType(&Name,
265 &ObjectTypeInitializer,
266 NULL,
267 &IoAdapterObjectType))) return FALSE;
268
269 /* Do the Controller Type */
270 RtlInitUnicodeString(&Name, L"Controller");
271 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CONTROLLER_OBJECT);
272 if (!NT_SUCCESS(ObCreateObjectType(&Name,
273 &ObjectTypeInitializer,
274 NULL,
275 &IoControllerObjectType))) return FALSE;
276
277 /* Do the Device Type. FIXME: Needs Delete Routine! */
278 RtlInitUnicodeString(&Name, L"Device");
279 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DEVICE_OBJECT);
280 ObjectTypeInitializer.ParseProcedure = IopParseDevice;
281 ObjectTypeInitializer.SecurityProcedure = IopSecurityFile;
282 if (!NT_SUCCESS(ObCreateObjectType(&Name,
283 &ObjectTypeInitializer,
284 NULL,
285 &IoDeviceObjectType))) return FALSE;
286
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,
295 NULL,
296 &IoDriverObjectType))) return FALSE;
297
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,
307 NULL,
308 &IoCompletionType))) return FALSE;
309
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 = IopSecurityFile;
320 ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile;
321 ObjectTypeInitializer.ParseProcedure = IopParseFile;
322 ObjectTypeInitializer.UseDefaultObject = FALSE;
323 if (!NT_SUCCESS(ObCreateObjectType(&Name,
324 &ObjectTypeInitializer,
325 NULL,
326 &IoFileObjectType))) return FALSE;
327
328 /* Success */
329 return TRUE;
330 }
331
332 BOOLEAN
333 INIT_FUNCTION
334 NTAPI
335 IopCreateRootDirectories()
336 {
337 OBJECT_ATTRIBUTES ObjectAttributes;
338 UNICODE_STRING DirName;
339 HANDLE Handle;
340
341 /* Create the '\Driver' object directory */
342 RtlInitUnicodeString(&DirName, L"\\Driver");
343 InitializeObjectAttributes(&ObjectAttributes,
344 &DirName,
345 OBJ_PERMANENT,
346 NULL,
347 NULL);
348 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
349 DIRECTORY_ALL_ACCESS,
350 &ObjectAttributes))) return FALSE;
351 NtClose(Handle);
352
353 /* Create the '\FileSystem' object directory */
354 RtlInitUnicodeString(&DirName, L"\\FileSystem");
355 InitializeObjectAttributes(&ObjectAttributes,
356 &DirName,
357 OBJ_PERMANENT,
358 NULL,
359 NULL);
360 if (!NT_SUCCESS(NtCreateDirectoryObject(&Handle,
361 DIRECTORY_ALL_ACCESS,
362 &ObjectAttributes))) return FALSE;
363 NtClose(Handle);
364
365 /* Return success */
366 return TRUE;
367 }
368
369 BOOLEAN
370 INIT_FUNCTION
371 NTAPI
372 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
373 {
374 OBJECT_ATTRIBUTES ObjectAttributes;
375 STRING DeviceString;
376 CHAR Buffer[256];
377 UNICODE_STRING DeviceName;
378 NTSTATUS Status;
379 HANDLE FileHandle;
380 IO_STATUS_BLOCK IoStatusBlock;
381 PFILE_OBJECT FileObject;
382
383 /* Build the ARC device name */
384 sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
385 RtlInitAnsiString(&DeviceString, Buffer);
386 Status = RtlAnsiStringToUnicodeString(&DeviceName, &DeviceString, TRUE);
387 if (!NT_SUCCESS(Status)) return FALSE;
388
389 /* Open it */
390 InitializeObjectAttributes(&ObjectAttributes,
391 &DeviceName,
392 OBJ_CASE_INSENSITIVE,
393 NULL,
394 NULL);
395 Status = ZwOpenFile(&FileHandle,
396 FILE_READ_ATTRIBUTES,
397 &ObjectAttributes,
398 &IoStatusBlock,
399 0,
400 FILE_NON_DIRECTORY_FILE);
401 if (!NT_SUCCESS(Status))
402 {
403 /* Fail */
404 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE,
405 (ULONG_PTR)&DeviceName,
406 Status,
407 0,
408 0);
409 }
410
411 /* Get the DO */
412 Status = ObReferenceObjectByHandle(FileHandle,
413 0,
414 IoFileObjectType,
415 KernelMode,
416 (PVOID *)&FileObject,
417 NULL);
418 if (!NT_SUCCESS(Status))
419 {
420 /* Fail */
421 RtlFreeUnicodeString(&DeviceName);
422 return FALSE;
423 }
424
425 /* Mark it as the boot partition */
426 FileObject->DeviceObject->Flags |= DO_SYSTEM_BOOT_PARTITION;
427
428 /* Save a copy of the DO for the I/O Error Logger */
429 ObReferenceObject(FileObject->DeviceObject);
430 IopErrorLogObject = FileObject->DeviceObject;
431
432 /* Cleanup and return success */
433 RtlFreeUnicodeString(&DeviceName);
434 NtClose(FileHandle);
435 ObDereferenceObject(FileObject);
436 return TRUE;
437 }
438
439 BOOLEAN
440 INIT_FUNCTION
441 NTAPI
442 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
443 {
444 LARGE_INTEGER ExpireTime;
445 NTSTATUS Status;
446 CHAR Buffer[256];
447 ANSI_STRING NtBootPath, RootString;
448
449 /* Initialize empty NT Boot Path */
450 RtlInitEmptyAnsiString(&NtBootPath, Buffer, sizeof(Buffer));
451
452 /* Initialize the lookaside lists */
453 IopInitLookasideLists();
454
455 /* Initialize all locks and lists */
456 ExInitializeResource(&IopDatabaseResource);
457 ExInitializeResource(&FileSystemListLock);
458 ExInitializeResource(&IopSecurityResource);
459 KeInitializeGuardedMutex(&FsChangeNotifyListLock);
460 KeInitializeGuardedMutex(&PnpNotifyListLock);
461 InitializeListHead(&IopDiskFsListHead);
462 InitializeListHead(&IopCdRomFsListHead);
463 InitializeListHead(&IopTapeFsListHead);
464 InitializeListHead(&IopNetworkFsListHead);
465 InitializeListHead(&DriverBootReinitListHead);
466 InitializeListHead(&DriverReinitListHead);
467 InitializeListHead(&PnpNotifyListHead);
468 InitializeListHead(&ShutdownListHead);
469 InitializeListHead(&FsChangeNotifyListHead);
470 InitializeListHead(&IopErrorLogListHead);
471 KeInitializeSpinLock(&CancelSpinLock);
472 KeInitializeSpinLock(&IoVpbLock);
473 KeInitializeSpinLock(&IoStatisticsLock);
474 KeInitializeSpinLock(&DriverReinitListLock);
475 KeInitializeSpinLock(&DriverBootReinitListLock);
476 KeInitializeSpinLock(&ShutdownListLock);
477 KeInitializeSpinLock(&IopLogListLock);
478
479 /* Initialize Timer List Lock */
480 KeInitializeSpinLock(&IopTimerLock);
481
482 /* Initialize Timer List */
483 InitializeListHead(&IopTimerQueueHead);
484
485 /* Initialize the DPC/Timer which will call the other Timer Routines */
486 ExpireTime.QuadPart = -10000000;
487 KeInitializeDpc(&IopTimerDpc, IopTimerDispatch, NULL);
488 KeInitializeTimerEx(&IopTimer, SynchronizationTimer);
489 KeSetTimerEx(&IopTimer, ExpireTime, 1000, &IopTimerDpc);
490
491 /* Create Object Types */
492 if (!IopCreateObjectTypes()) return FALSE;
493
494 /* Create Object Directories */
495 if (!IopCreateRootDirectories()) return FALSE;
496
497 /* Initialize PnP manager */
498 PnpInit();
499
500 /* Initialize PnP root relations */
501 IoSynchronousInvalidateDeviceRelations(IopRootDeviceNode->
502 PhysicalDeviceObject,
503 BusRelations);
504
505 /* Create the group driver list */
506 IoCreateDriverList();
507
508 /* Load boot start drivers */
509 IopInitializeBootDrivers();
510
511 /* Call back drivers that asked for */
512 IopReinitializeBootDrivers();
513
514 /* Create ARC names for boot devices */
515 IopCreateArcNames(LoaderBlock);
516
517 /* Mark the system boot partition */
518 if (!IopMarkBootPartition(LoaderBlock)) return FALSE;
519
520 /* Read KDB Data */
521 KdbInit();
522
523 /* I/O is now setup for disk access, so phase 3 */
524 KdInitSystem(3, LoaderBlock);
525
526 /* Load services for devices found by PnP manager */
527 IopInitializePnpServices(IopRootDeviceNode, FALSE);
528
529 /* Load system start drivers */
530 IopInitializeSystemDrivers();
531
532 /* Destroy the group driver list */
533 IoDestroyDriverList();
534
535 /* Reinitialize drivers that requested it */
536 IopReinitializeDrivers();
537
538 /* Convert SystemRoot from ARC to NT path */
539 Status = IopReassignSystemRoot(LoaderBlock, &NtBootPath);
540 if (!NT_SUCCESS(Status)) return FALSE;
541
542 /* Set the ANSI_STRING for the root path */
543 RootString.MaximumLength = NtSystemRoot.MaximumLength / sizeof(WCHAR);
544 RootString.Length = 0;
545 RootString.Buffer = ExAllocatePoolWithTag(PagedPool,
546 RootString.MaximumLength,
547 TAG_IO);
548
549 /* Convert the path into the ANSI_STRING */
550 Status = RtlUnicodeStringToAnsiString(&RootString, &NtSystemRoot, FALSE);
551 if (!NT_SUCCESS(Status)) return FALSE;
552
553 /* Assign drive letters */
554 IoAssignDriveLetters(LoaderBlock,
555 &NtBootPath,
556 (PUCHAR)RootString.Buffer,
557 &RootString);
558
559 /* Update system root */
560 Status = RtlAnsiStringToUnicodeString(&NtSystemRoot, &RootString, FALSE);
561 if (!NT_SUCCESS(Status)) return FALSE;
562
563 /* Load the System DLL and its Entrypoints */
564 if (!NT_SUCCESS(PsLocateSystemDll())) return FALSE;
565
566 /* Return success */
567 return TRUE;
568 }
569
570 /* EOF */