23f6761b85ccd899638230f1034d0178e58c4317
[reactos.git] / reactos / ntoskrnl / io / driver.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/driver.c
6 * PURPOSE: Loading and unloading of drivers
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Filip Navara (xnavara@volny.cz)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* ke/main.c */
19 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
20 extern ULONG KeTickCount;
21 extern BOOLEAN SetupMode;
22
23 NTSTATUS
24 LdrProcessModule(PVOID ModuleLoadBase,
25 PUNICODE_STRING ModuleName,
26 PLDR_DATA_TABLE_ENTRY *ModuleObject);
27
28 typedef struct _SERVICE_GROUP
29 {
30 LIST_ENTRY GroupListEntry;
31 UNICODE_STRING GroupName;
32 BOOLEAN ServicesRunning;
33 ULONG TagCount;
34 PULONG TagArray;
35 } SERVICE_GROUP, *PSERVICE_GROUP;
36
37 typedef struct _SERVICE
38 {
39 LIST_ENTRY ServiceListEntry;
40 UNICODE_STRING ServiceName;
41 UNICODE_STRING RegistryPath;
42 UNICODE_STRING ServiceGroup;
43 UNICODE_STRING ImagePath;
44
45 ULONG Start;
46 ULONG Type;
47 ULONG ErrorControl;
48 ULONG Tag;
49
50 /* BOOLEAN ServiceRunning;*/ // needed ??
51 } SERVICE, *PSERVICE;
52
53 typedef struct _DRIVER_REINIT_ITEM
54 {
55 LIST_ENTRY ItemEntry;
56 PDRIVER_OBJECT DriverObject;
57 PDRIVER_REINITIALIZE ReinitRoutine;
58 PVOID Context;
59 } DRIVER_REINIT_ITEM, *PDRIVER_REINIT_ITEM;
60
61 /* GLOBALS ********************************************************************/
62
63 static LIST_ENTRY DriverReinitListHead;
64 static KSPIN_LOCK DriverReinitListLock;
65 static PLIST_ENTRY DriverReinitTailEntry;
66
67 static PLIST_ENTRY DriverBootReinitTailEntry;
68 static LIST_ENTRY DriverBootReinitListHead;
69 static KSPIN_LOCK DriverBootReinitListLock;
70
71 static LIST_ENTRY GroupListHead = {NULL, NULL};
72 static LIST_ENTRY ServiceListHead = {NULL, NULL};
73
74 static UNICODE_STRING IopHardwareDatabaseKey =
75 RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
76
77 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
78
79 /* DECLARATIONS ***************************************************************/
80
81 VOID STDCALL
82 IopDeleteDriver(PVOID ObjectBody);
83
84 /* PRIVATE FUNCTIONS **********************************************************/
85
86 VOID
87 INIT_FUNCTION
88 IopInitDriverImplementation(VOID)
89 {
90 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
91 UNICODE_STRING Name;
92
93 DPRINT("Creating Registry Object Type\n");
94
95 /* Initialize the Driver object type */
96 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
97 RtlInitUnicodeString(&Name, L"Driver");
98 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
99 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DRIVER_OBJECT);
100 ObjectTypeInitializer.PoolType = NonPagedPool;
101 ObjectTypeInitializer.UseDefaultObject = TRUE;
102 ObjectTypeInitializer.DeleteProcedure = IopDeleteDriver;
103
104 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoDriverObjectType);
105
106 InitializeListHead(&DriverReinitListHead);
107 KeInitializeSpinLock(&DriverReinitListLock);
108 DriverReinitTailEntry = NULL;
109
110 InitializeListHead(&DriverBootReinitListHead);
111 KeInitializeSpinLock(&DriverBootReinitListLock);
112 DriverBootReinitTailEntry = NULL;
113 }
114
115 NTSTATUS STDCALL
116 IopInvalidDeviceRequest(
117 PDEVICE_OBJECT DeviceObject,
118 PIRP Irp)
119 {
120 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
121 Irp->IoStatus.Information = 0;
122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
123 return STATUS_INVALID_DEVICE_REQUEST;
124 }
125
126 VOID STDCALL
127 IopDeleteDriver(PVOID ObjectBody)
128 {
129 PDRIVER_OBJECT Object = ObjectBody;
130 KIRQL OldIrql;
131 PPRIVATE_DRIVER_EXTENSIONS DriverExtension, NextDriverExtension;
132
133 DPRINT("IopDeleteDriver(ObjectBody 0x%p)\n", ObjectBody);
134
135 ExFreePool(Object->DriverExtension);
136 ExFreePool(Object->DriverName.Buffer);
137
138 OldIrql = KeRaiseIrqlToDpcLevel();
139
140 for (DriverExtension = Object->DriverSection;
141 DriverExtension != NULL;
142 DriverExtension = NextDriverExtension)
143 {
144 NextDriverExtension = DriverExtension->Link;
145 ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
146 }
147
148 KfLowerIrql(OldIrql);
149 }
150
151 NTSTATUS FASTCALL
152 IopGetDriverObject(
153 PDRIVER_OBJECT *DriverObject,
154 PUNICODE_STRING ServiceName,
155 BOOLEAN FileSystem)
156 {
157 PDRIVER_OBJECT Object;
158 WCHAR NameBuffer[MAX_PATH];
159 UNICODE_STRING DriverName;
160 OBJECT_ATTRIBUTES ObjectAttributes;
161 NTSTATUS Status;
162
163 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
164 DriverObject, ServiceName, FileSystem);
165
166 *DriverObject = NULL;
167
168 /* Create ModuleName string */
169 if (ServiceName == NULL || ServiceName->Buffer == NULL)
170 /* We don't know which DriverObject we have to open */
171 return STATUS_INVALID_PARAMETER_2;
172
173 DriverName.Buffer = NameBuffer;
174 DriverName.Length = 0;
175 DriverName.MaximumLength = sizeof(NameBuffer);
176
177 if (FileSystem == TRUE)
178 RtlAppendUnicodeToString(&DriverName, FILESYSTEM_ROOT_NAME);
179 else
180 RtlAppendUnicodeToString(&DriverName, DRIVER_ROOT_NAME);
181 RtlAppendUnicodeStringToString(&DriverName, ServiceName);
182
183 DPRINT("Driver name: '%wZ'\n", &DriverName);
184
185 /* Initialize ObjectAttributes for driver object */
186 InitializeObjectAttributes(
187 &ObjectAttributes,
188 &DriverName,
189 OBJ_OPENIF | OBJ_KERNEL_HANDLE,
190 NULL,
191 NULL);
192
193 /* Open driver object */
194 Status = ObReferenceObjectByName(
195 &DriverName,
196 0, /* Attributes */
197 NULL, /* PassedAccessState */
198 0, /* DesiredAccess */
199 IoDriverObjectType,
200 KernelMode,
201 NULL, /* ParseContext */
202 (PVOID*)&Object);
203
204 if (!NT_SUCCESS(Status))
205 return Status;
206
207 *DriverObject = Object;
208
209 return STATUS_SUCCESS;
210 }
211
212 NTSTATUS FASTCALL
213 IopCreateDriverObject(
214 PDRIVER_OBJECT *DriverObject,
215 PUNICODE_STRING ServiceName,
216 ULONG CreateAttributes,
217 BOOLEAN FileSystem,
218 PVOID DriverImageStart,
219 ULONG DriverImageSize)
220 {
221 PDRIVER_OBJECT Object;
222 WCHAR NameBuffer[MAX_PATH];
223 UNICODE_STRING DriverName;
224 OBJECT_ATTRIBUTES ObjectAttributes;
225 NTSTATUS Status;
226 ULONG i;
227 PWSTR Buffer = NULL;
228
229 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
230 DriverObject, ServiceName, FileSystem, DriverImageStart, DriverImageSize);
231
232 *DriverObject = NULL;
233
234 /* Create ModuleName string */
235 if (ServiceName != NULL && ServiceName->Buffer != NULL)
236 {
237 if (FileSystem == TRUE)
238 wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
239 else
240 wcscpy(NameBuffer, DRIVER_ROOT_NAME);
241 wcscat(NameBuffer, ServiceName->Buffer);
242
243 RtlInitUnicodeString(&DriverName, NameBuffer);
244 DPRINT("Driver name: '%wZ'\n", &DriverName);
245
246 Buffer = (PWSTR)ExAllocatePool(PagedPool, DriverName.Length + sizeof(WCHAR));
247 /* If we don't success, it is not a problem. Our driver
248 * object will not have associated driver name... */
249 }
250 else
251 {
252 RtlInitUnicodeString(&DriverName, NULL);
253 }
254
255 /* Initialize ObjectAttributes for driver object */
256 InitializeObjectAttributes(
257 &ObjectAttributes,
258 &DriverName,
259 CreateAttributes | OBJ_PERMANENT,
260 NULL,
261 NULL);
262
263 /* Create driver object */
264 Status = ObCreateObject(
265 KernelMode,
266 IoDriverObjectType,
267 &ObjectAttributes,
268 KernelMode,
269 NULL,
270 sizeof(DRIVER_OBJECT),
271 0,
272 0,
273 (PVOID*)&Object);
274
275 if (!NT_SUCCESS(Status))
276 {
277 return Status;
278 }
279
280 Status = ObInsertObject(Object,
281 NULL,
282 FILE_ALL_ACCESS,
283 0,
284 NULL,
285 NULL);
286 if (!NT_SUCCESS(Status))
287 {
288 return Status;
289 }
290
291 /* Create driver extension */
292 Object->DriverExtension = (PDRIVER_EXTENSION)
293 ExAllocatePoolWithTag(
294 NonPagedPool,
295 sizeof(DRIVER_EXTENSION),
296 TAG_DRIVER_EXTENSION);
297
298 if (Object->DriverExtension == NULL)
299 {
300 return STATUS_NO_MEMORY;
301 }
302
303 RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
304
305 Object->Type = IO_TYPE_DRIVER;
306
307 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
308 Object->MajorFunction[i] = IopInvalidDeviceRequest;
309
310 Object->HardwareDatabase = &IopHardwareDatabaseKey;
311
312 Object->DriverStart = DriverImageStart;
313 Object->DriverSize = DriverImageSize;
314 if (Buffer)
315 {
316 if (!Object->DriverName.Buffer)
317 {
318 Object->DriverName.Buffer = Buffer;
319 Object->DriverName.Length = DriverName.Length;
320 Object->DriverName.MaximumLength = DriverName.Length + sizeof(WCHAR);
321 RtlCopyMemory(Object->DriverName.Buffer, DriverName.Buffer, DriverName.Length);
322 Object->DriverName.Buffer[Object->DriverName.Length / sizeof(WCHAR)] = L'\0';
323 }
324 else
325 ExFreePool(Buffer);
326 }
327
328 *DriverObject = Object;
329
330 return STATUS_SUCCESS;
331 }
332
333 /*
334 * IopDisplayLoadingMessage
335 *
336 * Display 'Loading XXX...' message.
337 */
338
339 VOID
340 FASTCALL
341 INIT_FUNCTION
342 IopDisplayLoadingMessage(PVOID ServiceName,
343 BOOLEAN Unicode)
344 {
345 CHAR TextBuffer[256];
346 if (SetupMode) return;
347 if (Unicode)
348 {
349 sprintf(TextBuffer, "Loading %S...\n", (PWCHAR)ServiceName);
350 }
351 else
352 {
353 sprintf(TextBuffer, "Loading %s...\n", (PCHAR)ServiceName);
354 }
355 HalDisplayString(TextBuffer);
356 }
357
358 /*
359 * IopNormalizeImagePath
360 *
361 * Normalize an image path to contain complete path.
362 *
363 * Parameters
364 * ImagePath
365 * The input path and on exit the result path. ImagePath.Buffer
366 * must be allocated by ExAllocatePool on input. Caller is responsible
367 * for freeing the buffer when it's no longer needed.
368 *
369 * ServiceName
370 * Name of the service that ImagePath belongs to.
371 *
372 * Return Value
373 * Status
374 *
375 * Remarks
376 * The input image path isn't freed on error.
377 */
378
379 NTSTATUS FASTCALL
380 IopNormalizeImagePath(
381 IN OUT PUNICODE_STRING ImagePath,
382 IN PUNICODE_STRING ServiceName)
383 {
384 UNICODE_STRING InputImagePath;
385
386 RtlCopyMemory(
387 &InputImagePath,
388 ImagePath,
389 sizeof(UNICODE_STRING));
390
391 if (InputImagePath.Length == 0)
392 {
393 ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
394 ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
395 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
396 if (ImagePath->Buffer == NULL)
397 return STATUS_NO_MEMORY;
398
399 wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
400 wcscat(ImagePath->Buffer, ServiceName->Buffer);
401 wcscat(ImagePath->Buffer, L".sys");
402 } else
403 if (InputImagePath.Buffer[0] != L'\\')
404 {
405 ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
406 ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
407 ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
408 if (ImagePath->Buffer == NULL)
409 return STATUS_NO_MEMORY;
410
411 wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
412 wcscat(ImagePath->Buffer, InputImagePath.Buffer);
413 ExFreePool(InputImagePath.Buffer);
414 }
415
416 return STATUS_SUCCESS;
417 }
418
419 /*
420 * IopLoadServiceModule
421 *
422 * Load a module specified by registry settings for service.
423 *
424 * Parameters
425 * ServiceName
426 * Name of the service to load.
427 *
428 * Return Value
429 * Status
430 */
431
432 NTSTATUS FASTCALL
433 IopLoadServiceModule(
434 IN PUNICODE_STRING ServiceName,
435 OUT PLDR_DATA_TABLE_ENTRY *ModuleObject)
436 {
437 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
438 ULONG ServiceStart;
439 UNICODE_STRING ServiceImagePath;
440 NTSTATUS Status;
441
442 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
443
444 /*
445 * Get information about the service.
446 */
447
448 RtlZeroMemory(QueryTable, sizeof(QueryTable));
449
450 RtlInitUnicodeString(&ServiceImagePath, NULL);
451
452 QueryTable[0].Name = L"Start";
453 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
454 QueryTable[0].EntryContext = &ServiceStart;
455
456 QueryTable[1].Name = L"ImagePath";
457 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
458 QueryTable[1].EntryContext = &ServiceImagePath;
459
460 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
461 ServiceName->Buffer, QueryTable, NULL, NULL);
462
463 if (!NT_SUCCESS(Status))
464 {
465 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
466 return Status;
467 }
468
469 IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
470
471 /*
472 * Normalize the image path for all later processing.
473 */
474
475 Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
476
477 if (!NT_SUCCESS(Status))
478 {
479 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
480 return Status;
481 }
482
483 /*
484 * Load the module.
485 */
486
487 *ModuleObject = LdrGetModuleObject(&ServiceImagePath);
488
489 if (*ModuleObject == NULL)
490 {
491 Status = STATUS_UNSUCCESSFUL;
492
493 /*
494 * Special case for boot modules that were loaded by boot loader.
495 */
496
497 if (ServiceStart == 0)
498 {
499 ULONG i;
500 CHAR SearchName[256];
501 PCHAR ModuleName;
502 PLOADER_MODULE KeLoaderModules =
503 (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
504
505 /*
506 * FIXME:
507 * Improve this searching algorithm by using the image name
508 * stored in registry entry ImageName and use the whole path
509 * (requires change in FreeLoader).
510 */
511
512 _snprintf(SearchName, sizeof(SearchName), "%wZ.sys", ServiceName);
513 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
514 {
515 ModuleName = (PCHAR)KeLoaderModules[i].String;
516 if (!_stricmp(ModuleName, SearchName))
517 {
518 DPRINT("Initializing boot module\n");
519
520 /* Tell, that the module is already loaded */
521 KeLoaderModules[i].Reserved = 1;
522
523 Status = LdrProcessModule(
524 (PVOID)KeLoaderModules[i].ModStart,
525 &ServiceImagePath,
526 ModuleObject);
527
528 KDB_SYMBOLFILE_HOOK(SearchName);
529
530 break;
531 }
532 }
533 }
534
535 /*
536 * Case for rest of the drivers (except disabled)
537 */
538
539 else if (ServiceStart < 4)
540 {
541 DPRINT("Loading module\n");
542 Status = LdrLoadModule(&ServiceImagePath, ModuleObject);
543 }
544 }
545 else
546 {
547 DPRINT("Module already loaded\n");
548 Status = STATUS_IMAGE_ALREADY_LOADED;
549 }
550
551 ExFreePool(ServiceImagePath.Buffer);
552
553 /*
554 * Now check if the module was loaded successfully.
555 */
556
557 if (!NT_SUCCESS(Status))
558 {
559 DPRINT("Module loading failed (Status %x)\n", Status);
560 }
561
562 DPRINT("Module loading (Status %x)\n", Status);
563
564 return Status;
565 }
566
567 /*
568 * IopInitializeDriverModule
569 *
570 * Initalize a loaded driver.
571 *
572 * Parameters
573 * DeviceNode
574 * Pointer to device node.
575 *
576 * ModuleObject
577 * Module object representing the driver. It can be retrieve by
578 * IopLoadServiceModule.
579 *
580 * ServiceName
581 * Name of the service (as in registry).
582 *
583 * FileSystemDriver
584 * Set to TRUE for file system drivers.
585 *
586 * DriverObject
587 * On successful return this contains the driver object representing
588 * the loaded driver.
589 */
590
591 NTSTATUS FASTCALL
592 IopInitializeDriverModule(
593 IN PDEVICE_NODE DeviceNode,
594 IN PLDR_DATA_TABLE_ENTRY ModuleObject,
595 IN PUNICODE_STRING ServiceName,
596 IN BOOLEAN FileSystemDriver,
597 OUT PDRIVER_OBJECT *DriverObject)
598 {
599 const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
600 UNICODE_STRING RegistryKey;
601 PDRIVER_INITIALIZE DriverEntry;
602 NTSTATUS Status;
603
604 DriverEntry = ModuleObject->EntryPoint;
605
606 if (ServiceName != NULL && ServiceName->Length != 0)
607 {
608 RegistryKey.Length = 0;
609 RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
610 RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
611 if (RegistryKey.Buffer == NULL)
612 {
613 return STATUS_INSUFFICIENT_RESOURCES;
614 }
615 RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
616 RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
617 }
618 else
619 {
620 RtlInitUnicodeString(&RegistryKey, NULL);
621 }
622
623 Status = IopCreateDriverObject(
624 DriverObject,
625 ServiceName,
626 0,
627 FileSystemDriver,
628 ModuleObject->DllBase,
629 ModuleObject->SizeOfImage);
630
631 if (!NT_SUCCESS(Status))
632 {
633 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status);
634 return Status;
635 }
636
637 DPRINT("RegistryKey: %wZ\n", &RegistryKey);
638 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
639
640 IopMarkLastReinitializeDriver();
641
642 Status = DriverEntry(*DriverObject, &RegistryKey);
643
644 RtlFreeUnicodeString(&RegistryKey);
645
646 if (!NT_SUCCESS(Status))
647 {
648 ObMakeTemporaryObject(*DriverObject);
649 ObDereferenceObject(*DriverObject);
650 return Status;
651 }
652
653 IopReinitializeDrivers();
654
655 return STATUS_SUCCESS;
656 }
657
658 /*
659 * IopAttachFilterDriversCallback
660 *
661 * Internal routine used by IopAttachFilterDrivers.
662 */
663
664 NTSTATUS STDCALL
665 IopAttachFilterDriversCallback(
666 PWSTR ValueName,
667 ULONG ValueType,
668 PVOID ValueData,
669 ULONG ValueLength,
670 PVOID Context,
671 PVOID EntryContext)
672 {
673 PDEVICE_NODE DeviceNode = Context;
674 UNICODE_STRING ServiceName;
675 PWCHAR Filters;
676 PLDR_DATA_TABLE_ENTRY ModuleObject;
677 PDRIVER_OBJECT DriverObject;
678 NTSTATUS Status;
679
680 for (Filters = ValueData;
681 ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
682 *Filters != 0;
683 Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
684 {
685 DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
686 ServiceName.Buffer = Filters;
687 ServiceName.MaximumLength =
688 ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
689
690 /* Load and initialize the filter driver */
691 Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
692 if (Status != STATUS_IMAGE_ALREADY_LOADED)
693 {
694 if (!NT_SUCCESS(Status))
695 continue;
696
697 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
698 FALSE, &DriverObject);
699 if (!NT_SUCCESS(Status))
700 continue;
701 }
702 else
703 {
704 /* get existing DriverObject pointer */
705 Status = IopGetDriverObject(
706 &DriverObject,
707 &ServiceName,
708 FALSE);
709 if (!NT_SUCCESS(Status))
710 continue;
711 }
712
713 Status = IopInitializeDevice(DeviceNode, DriverObject);
714 if (!NT_SUCCESS(Status))
715 continue;
716 }
717
718 return STATUS_SUCCESS;
719 }
720
721 /*
722 * IopAttachFilterDrivers
723 *
724 * Load filter drivers for specified device node.
725 *
726 * Parameters
727 * Lower
728 * Set to TRUE for loading lower level filters or FALSE for upper
729 * level filters.
730 */
731
732 NTSTATUS FASTCALL
733 IopAttachFilterDrivers(
734 PDEVICE_NODE DeviceNode,
735 BOOLEAN Lower)
736 {
737 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
738 PWCHAR KeyBuffer;
739 UNICODE_STRING Class;
740 WCHAR ClassBuffer[40];
741 NTSTATUS Status;
742
743 /*
744 * First load the device filters
745 */
746
747 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
748 if (Lower)
749 QueryTable[0].Name = L"LowerFilters";
750 else
751 QueryTable[0].Name = L"UpperFilters";
752 QueryTable[0].EntryContext = NULL;
753 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
754 QueryTable[1].QueryRoutine = NULL;
755 QueryTable[1].Name = NULL;
756
757 KeyBuffer = ExAllocatePool(
758 PagedPool,
759 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
760 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
761 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
762
763 RtlQueryRegistryValues(
764 RTL_REGISTRY_ABSOLUTE,
765 KeyBuffer,
766 QueryTable,
767 DeviceNode,
768 NULL);
769
770 /*
771 * Now get the class GUID
772 */
773
774 Class.Length = 0;
775 Class.MaximumLength = 40 * sizeof(WCHAR);
776 Class.Buffer = ClassBuffer;
777 QueryTable[0].QueryRoutine = NULL;
778 QueryTable[0].Name = L"ClassGUID";
779 QueryTable[0].EntryContext = &Class;
780 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
781
782 Status = RtlQueryRegistryValues(
783 RTL_REGISTRY_ABSOLUTE,
784 KeyBuffer,
785 QueryTable,
786 DeviceNode,
787 NULL);
788
789 ExFreePool(KeyBuffer);
790
791 /*
792 * Load the class filter driver
793 */
794
795 if (NT_SUCCESS(Status))
796 {
797 QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
798 if (Lower)
799 QueryTable[0].Name = L"LowerFilters";
800 else
801 QueryTable[0].Name = L"UpperFilters";
802 QueryTable[0].EntryContext = NULL;
803 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
804
805 KeyBuffer = ExAllocatePool(PagedPool, (58 * sizeof(WCHAR)) + Class.Length);
806 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
807 wcscat(KeyBuffer, ClassBuffer);
808
809 RtlQueryRegistryValues(
810 RTL_REGISTRY_ABSOLUTE,
811 KeyBuffer,
812 QueryTable,
813 DeviceNode,
814 NULL);
815
816 ExFreePool(KeyBuffer);
817 }
818
819 return STATUS_SUCCESS;
820 }
821
822 static NTSTATUS STDCALL
823 IopGetGroupOrderList(PWSTR ValueName,
824 ULONG ValueType,
825 PVOID ValueData,
826 ULONG ValueLength,
827 PVOID Context,
828 PVOID EntryContext)
829 {
830 PSERVICE_GROUP Group;
831
832 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
833 ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
834
835 if (ValueType == REG_BINARY &&
836 ValueData != NULL &&
837 ValueLength >= sizeof(DWORD) &&
838 ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
839 {
840 Group = (PSERVICE_GROUP)Context;
841 Group->TagCount = ((PULONG)ValueData)[0];
842 if (Group->TagCount > 0)
843 {
844 if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
845 {
846 Group->TagArray = ExAllocatePool(NonPagedPool, Group->TagCount * sizeof(DWORD));
847 if (Group->TagArray == NULL)
848 {
849 Group->TagCount = 0;
850 return STATUS_INSUFFICIENT_RESOURCES;
851 }
852 memcpy(Group->TagArray, (PULONG)ValueData + 1, Group->TagCount * sizeof(DWORD));
853 }
854 else
855 {
856 Group->TagCount = 0;
857 return STATUS_UNSUCCESSFUL;
858 }
859 }
860 }
861 return STATUS_SUCCESS;
862 }
863
864 static NTSTATUS STDCALL
865 IopCreateGroupListEntry(PWSTR ValueName,
866 ULONG ValueType,
867 PVOID ValueData,
868 ULONG ValueLength,
869 PVOID Context,
870 PVOID EntryContext)
871 {
872 PSERVICE_GROUP Group;
873 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
874 NTSTATUS Status;
875
876
877 if (ValueType == REG_SZ)
878 {
879 DPRINT("GroupName: '%S'\n", (PWCHAR)ValueData);
880
881 Group = ExAllocatePool(NonPagedPool,
882 sizeof(SERVICE_GROUP));
883 if (Group == NULL)
884 {
885 return(STATUS_INSUFFICIENT_RESOURCES);
886 }
887
888 RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
889
890 if (!RtlCreateUnicodeString(&Group->GroupName, (PWSTR)ValueData))
891 {
892 ExFreePool(Group);
893 return(STATUS_INSUFFICIENT_RESOURCES);
894 }
895
896 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
897 QueryTable[0].Name = (PWSTR)ValueData;
898 QueryTable[0].QueryRoutine = IopGetGroupOrderList;
899
900 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
901 L"GroupOrderList",
902 QueryTable,
903 (PVOID)Group,
904 NULL);
905 DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
906
907 InsertTailList(&GroupListHead,
908 &Group->GroupListEntry);
909 }
910
911 return(STATUS_SUCCESS);
912 }
913
914
915 static NTSTATUS STDCALL
916 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
917 {
918 RTL_QUERY_REGISTRY_TABLE QueryTable[7];
919 PSERVICE Service;
920 NTSTATUS Status;
921
922 DPRINT("ServiceName: '%wZ'\n", ServiceName);
923
924 /* Allocate service entry */
925 Service = (PSERVICE)ExAllocatePool(NonPagedPool, sizeof(SERVICE));
926 if (Service == NULL)
927 {
928 DPRINT1("ExAllocatePool() failed\n");
929 return(STATUS_INSUFFICIENT_RESOURCES);
930 }
931 RtlZeroMemory(Service, sizeof(SERVICE));
932
933 /* Get service data */
934 RtlZeroMemory(&QueryTable,
935 sizeof(QueryTable));
936
937 QueryTable[0].Name = L"Start";
938 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
939 QueryTable[0].EntryContext = &Service->Start;
940
941 QueryTable[1].Name = L"Type";
942 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
943 QueryTable[1].EntryContext = &Service->Type;
944
945 QueryTable[2].Name = L"ErrorControl";
946 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
947 QueryTable[2].EntryContext = &Service->ErrorControl;
948
949 QueryTable[3].Name = L"Group";
950 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
951 QueryTable[3].EntryContext = &Service->ServiceGroup;
952
953 QueryTable[4].Name = L"ImagePath";
954 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
955 QueryTable[4].EntryContext = &Service->ImagePath;
956
957 QueryTable[5].Name = L"Tag";
958 QueryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
959 QueryTable[5].EntryContext = &Service->Tag;
960
961 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
962 ServiceName->Buffer,
963 QueryTable,
964 NULL,
965 NULL);
966 if (!NT_SUCCESS(Status) || Service->Start > 1)
967 {
968 /*
969 * If something goes wrong during RtlQueryRegistryValues
970 * it'll just drop everything on the floor and return,
971 * so you have to check if the buffers were filled.
972 * Luckily we zerofilled the Service.
973 */
974 if (Service->ServiceGroup.Buffer)
975 {
976 ExFreePool(Service->ServiceGroup.Buffer);
977 }
978 if (Service->ImagePath.Buffer)
979 {
980 ExFreePool(Service->ImagePath.Buffer);
981 }
982 ExFreePool(Service);
983 return(Status);
984 }
985
986 /* Copy service name */
987 Service->ServiceName.Length = ServiceName->Length;
988 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
989 Service->ServiceName.Buffer = ExAllocatePool(NonPagedPool,
990 Service->ServiceName.MaximumLength);
991 RtlCopyMemory(Service->ServiceName.Buffer,
992 ServiceName->Buffer,
993 ServiceName->Length);
994 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
995
996 /* Build registry path */
997 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
998 Service->RegistryPath.Buffer = ExAllocatePool(NonPagedPool,
999 MAX_PATH * sizeof(WCHAR));
1000 wcscpy(Service->RegistryPath.Buffer,
1001 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1002 wcscat(Service->RegistryPath.Buffer,
1003 Service->ServiceName.Buffer);
1004 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
1005
1006 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
1007 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
1008 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
1009 DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
1010 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1011 Service->Start, Service->Type, Service->Tag, Service->ErrorControl);
1012
1013 /* Append service entry */
1014 InsertTailList(&ServiceListHead,
1015 &Service->ServiceListEntry);
1016
1017 return(STATUS_SUCCESS);
1018 }
1019
1020
1021 NTSTATUS INIT_FUNCTION
1022 IoCreateDriverList(VOID)
1023 {
1024 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1025 PKEY_BASIC_INFORMATION KeyInfo = NULL;
1026 OBJECT_ATTRIBUTES ObjectAttributes;
1027 UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1028 UNICODE_STRING SubKeyName;
1029 HANDLE KeyHandle;
1030 NTSTATUS Status;
1031 ULONG Index;
1032
1033 ULONG KeyInfoLength = 0;
1034 ULONG ReturnedLength;
1035
1036 DPRINT("IoCreateDriverList() called\n");
1037
1038 /* Initialize basic variables */
1039 InitializeListHead(&GroupListHead);
1040 InitializeListHead(&ServiceListHead);
1041
1042 /* Build group order list */
1043 RtlZeroMemory(&QueryTable,
1044 sizeof(QueryTable));
1045
1046 QueryTable[0].Name = L"List";
1047 QueryTable[0].QueryRoutine = IopCreateGroupListEntry;
1048
1049 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
1050 L"ServiceGroupOrder",
1051 QueryTable,
1052 NULL,
1053 NULL);
1054 if (!NT_SUCCESS(Status))
1055 return(Status);
1056
1057 /* Enumerate services and create the service list */
1058 InitializeObjectAttributes(&ObjectAttributes,
1059 &ServicesKeyName,
1060 OBJ_CASE_INSENSITIVE,
1061 NULL,
1062 NULL);
1063
1064 Status = ZwOpenKey(&KeyHandle,
1065 KEY_ENUMERATE_SUB_KEYS,
1066 &ObjectAttributes);
1067 if (!NT_SUCCESS(Status))
1068 {
1069 return(Status);
1070 }
1071
1072 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
1073 KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
1074 if (KeyInfo == NULL)
1075 {
1076 ZwClose(KeyHandle);
1077 return(STATUS_INSUFFICIENT_RESOURCES);
1078 }
1079
1080 Index = 0;
1081 while (TRUE)
1082 {
1083 Status = ZwEnumerateKey(KeyHandle,
1084 Index,
1085 KeyBasicInformation,
1086 KeyInfo,
1087 KeyInfoLength,
1088 &ReturnedLength);
1089 if (NT_SUCCESS(Status))
1090 {
1091 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
1092 {
1093
1094 SubKeyName.Length = KeyInfo->NameLength;
1095 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
1096 SubKeyName.Buffer = KeyInfo->Name;
1097 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
1098
1099 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
1100 IopCreateServiceListEntry(&SubKeyName);
1101 }
1102 }
1103
1104 if (!NT_SUCCESS(Status))
1105 break;
1106
1107 Index++;
1108 }
1109
1110 ExFreePool(KeyInfo);
1111 ZwClose(KeyHandle);
1112
1113 DPRINT("IoCreateDriverList() done\n");
1114
1115 return(STATUS_SUCCESS);
1116 }
1117
1118 NTSTATUS INIT_FUNCTION
1119 IoDestroyDriverList(VOID)
1120 {
1121 PLIST_ENTRY GroupEntry;
1122 PLIST_ENTRY ServiceEntry;
1123 PSERVICE_GROUP CurrentGroup;
1124 PSERVICE CurrentService;
1125
1126 DPRINT("IoDestroyDriverList() called\n");
1127
1128 /* Destroy group list */
1129 GroupEntry = GroupListHead.Flink;
1130 while (GroupEntry != &GroupListHead)
1131 {
1132 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1133
1134 ExFreePool(CurrentGroup->GroupName.Buffer);
1135 RemoveEntryList(GroupEntry);
1136 if (CurrentGroup->TagArray)
1137 {
1138 ExFreePool(CurrentGroup->TagArray);
1139 }
1140 ExFreePool(CurrentGroup);
1141
1142 GroupEntry = GroupListHead.Flink;
1143 }
1144
1145 /* Destroy service list */
1146 ServiceEntry = ServiceListHead.Flink;
1147 while (ServiceEntry != &ServiceListHead)
1148 {
1149 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1150
1151 ExFreePool(CurrentService->ServiceName.Buffer);
1152 ExFreePool(CurrentService->RegistryPath.Buffer);
1153 ExFreePool(CurrentService->ServiceGroup.Buffer);
1154 ExFreePool(CurrentService->ImagePath.Buffer);
1155 RemoveEntryList(ServiceEntry);
1156 ExFreePool(CurrentService);
1157
1158 ServiceEntry = ServiceListHead.Flink;
1159 }
1160
1161 DPRINT("IoDestroyDriverList() done\n");
1162
1163 return(STATUS_SUCCESS);
1164 }
1165
1166 VOID STATIC INIT_FUNCTION
1167 MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
1168 {
1169 ULONG i;
1170
1171 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
1172 {
1173 MmDeleteVirtualMapping(NULL, (char*)StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
1174 }
1175 }
1176
1177 /*
1178 * IopInitializeBuiltinDriver
1179 *
1180 * Initialize a driver that is already loaded in memory.
1181 */
1182
1183 NTSTATUS FASTCALL INIT_FUNCTION
1184 IopInitializeBuiltinDriver(
1185 PDEVICE_NODE ModuleDeviceNode,
1186 PVOID ModuleLoadBase,
1187 PCHAR FileName,
1188 ULONG ModuleLength)
1189 {
1190 PLDR_DATA_TABLE_ENTRY ModuleObject;
1191 PDEVICE_NODE DeviceNode;
1192 PDRIVER_OBJECT DriverObject;
1193 NTSTATUS Status;
1194 PCHAR FileNameWithoutPath;
1195 LPWSTR FileExtension;
1196
1197 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1198 FileName, ModuleLoadBase, ModuleLength);
1199
1200 /*
1201 * Display 'Loading XXX...' message
1202 */
1203 IopDisplayLoadingMessage(FileName, FALSE);
1204
1205 /*
1206 * Determine the right device object
1207 */
1208
1209 if (ModuleDeviceNode == NULL)
1210 {
1211 /* Use IopRootDeviceNode for now */
1212 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1213 if (!NT_SUCCESS(Status))
1214 {
1215 CPRINT("Driver '%s' load failed, status (%x)\n", FileName, Status);
1216 return(Status);
1217 }
1218 } else
1219 {
1220 DeviceNode = ModuleDeviceNode;
1221 }
1222
1223 /*
1224 * Generate filename without path (not needed by freeldr)
1225 */
1226
1227 FileNameWithoutPath = strrchr(FileName, '\\');
1228 if (FileNameWithoutPath == NULL)
1229 {
1230 FileNameWithoutPath = FileName;
1231 }
1232
1233 /*
1234 * Load the module
1235 */
1236
1237 RtlCreateUnicodeStringFromAsciiz(&DeviceNode->ServiceName,
1238 FileNameWithoutPath);
1239 Status = LdrProcessModule(ModuleLoadBase, &DeviceNode->ServiceName,
1240 &ModuleObject);
1241 if (!NT_SUCCESS(Status))
1242 {
1243 if (ModuleDeviceNode == NULL)
1244 IopFreeDeviceNode(DeviceNode);
1245 CPRINT("Driver '%s' load failed, status (%x)\n", FileName, Status);
1246 return Status;
1247 }
1248
1249 /* Load symbols */
1250 KDB_SYMBOLFILE_HOOK(FileName);
1251
1252 /*
1253 * Strip the file extension from ServiceName
1254 */
1255
1256 FileExtension = wcsrchr(DeviceNode->ServiceName.Buffer, '.');
1257 if (FileExtension != NULL)
1258 {
1259 DeviceNode->ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
1260 FileExtension[0] = 0;
1261 }
1262
1263 /*
1264 * Initialize the driver
1265 */
1266
1267 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
1268 &DeviceNode->ServiceName, FALSE, &DriverObject);
1269
1270 if (!NT_SUCCESS(Status))
1271 {
1272 if (ModuleDeviceNode == NULL)
1273 IopFreeDeviceNode(DeviceNode);
1274 CPRINT("Driver '%s' load failed, status (%x)\n", FileName, Status);
1275 return Status;
1276 }
1277
1278 Status = IopInitializeDevice(DeviceNode, DriverObject);
1279 if (NT_SUCCESS(Status))
1280 {
1281 Status = IopStartDevice(DeviceNode);
1282 }
1283
1284 return Status;
1285 }
1286
1287 /*
1288 * IopInitializeBootDrivers
1289 *
1290 * Initialize boot drivers and free memory for boot files.
1291 *
1292 * Parameters
1293 * None
1294 *
1295 * Return Value
1296 * None
1297 */
1298
1299 VOID FASTCALL
1300 IopInitializeBootDrivers(VOID)
1301 {
1302 ULONG BootDriverCount;
1303 ULONG ModuleStart;
1304 ULONG ModuleSize;
1305 ULONG ModuleLoaded;
1306 PCHAR ModuleName;
1307 PCHAR Extension;
1308 PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
1309 ULONG i;
1310 UNICODE_STRING DriverName;
1311 NTSTATUS Status;
1312
1313 DPRINT("IopInitializeBootDrivers()\n");
1314
1315 BootDriverCount = 0;
1316 for (i = 0; i < KeLoaderBlock.ModsCount; i++)
1317 {
1318 ModuleStart = KeLoaderModules[i].ModStart;
1319 ModuleSize = KeLoaderModules[i].ModEnd - ModuleStart;
1320 ModuleName = (PCHAR)KeLoaderModules[i].String;
1321 ModuleLoaded = KeLoaderModules[i].Reserved;
1322 Extension = strrchr(ModuleName, '.');
1323 if (Extension == NULL)
1324 Extension = "";
1325
1326 if (!_stricmp(Extension, ".sym") || !_stricmp(Extension, ".dll"))
1327 {
1328 /* Process symbols for *.exe and *.dll */
1329 KDB_SYMBOLFILE_HOOK(ModuleName);
1330
1331 /* Log *.exe and *.dll files */
1332 RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
1333 IopBootLog(&DriverName, TRUE);
1334 RtlFreeUnicodeString(&DriverName);
1335 }
1336 else if (!_stricmp(Extension, ".sys"))
1337 {
1338 /* Initialize and log boot start driver */
1339 if (!ModuleLoaded)
1340 {
1341 Status = IopInitializeBuiltinDriver(NULL,
1342 (PVOID)ModuleStart,
1343 ModuleName,
1344 ModuleSize);
1345 RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
1346 IopBootLog(&DriverName, NT_SUCCESS(Status) ? TRUE : FALSE);
1347 RtlFreeUnicodeString(&DriverName);
1348 }
1349 BootDriverCount++;
1350 }
1351 }
1352
1353 /*
1354 * Free memory for all boot files, except ntoskrnl.exe.
1355 */
1356 for (i = 1; i < KeLoaderBlock.ModsCount; i++)
1357 {
1358 MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
1359 KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
1360 }
1361
1362 KeLoaderBlock.ModsCount = 0;
1363
1364 if (BootDriverCount == 0)
1365 {
1366 DbgPrint("No boot drivers available.\n");
1367 KEBUGCHECK(0);
1368 }
1369 }
1370
1371 static INIT_FUNCTION NTSTATUS
1372 IopLoadDriver(PSERVICE Service)
1373 {
1374 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1375
1376 IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE);
1377 Status = ZwLoadDriver(&Service->RegistryPath);
1378 IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);
1379 if (!NT_SUCCESS(Status))
1380 {
1381 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status);
1382 #if 0
1383 if (Service->ErrorControl == 1)
1384 {
1385 /* Log error */
1386 }
1387 else if (Service->ErrorControl == 2)
1388 {
1389 if (IsLastKnownGood == FALSE)
1390 {
1391 /* Boot last known good configuration */
1392 }
1393 }
1394 else if (Service->ErrorControl == 3)
1395 {
1396 if (IsLastKnownGood == FALSE)
1397 {
1398 /* Boot last known good configuration */
1399 }
1400 else
1401 {
1402 /* BSOD! */
1403 }
1404 }
1405 #endif
1406 }
1407 return Status;
1408 }
1409
1410
1411 /*
1412 * IopInitializeSystemDrivers
1413 *
1414 * Load drivers marked as system start.
1415 *
1416 * Parameters
1417 * None
1418 *
1419 * Return Value
1420 * None
1421 */
1422
1423 VOID FASTCALL
1424 IopInitializeSystemDrivers(VOID)
1425 {
1426 PLIST_ENTRY GroupEntry;
1427 PLIST_ENTRY ServiceEntry;
1428 PSERVICE_GROUP CurrentGroup;
1429 PSERVICE CurrentService;
1430 NTSTATUS Status;
1431 ULONG i;
1432
1433 DPRINT("IopInitializeSystemDrivers()\n");
1434
1435 GroupEntry = GroupListHead.Flink;
1436 while (GroupEntry != &GroupListHead)
1437 {
1438 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1439
1440 DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
1441
1442 /* Load all drivers with a valid tag */
1443 for (i = 0; i < CurrentGroup->TagCount; i++)
1444 {
1445 ServiceEntry = ServiceListHead.Flink;
1446 while (ServiceEntry != &ServiceListHead)
1447 {
1448 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1449
1450 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1451 &CurrentService->ServiceGroup, TRUE) == 0) &&
1452 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/) &&
1453 (CurrentService->Tag == CurrentGroup->TagArray[i]))
1454 {
1455 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1456 Status = IopLoadDriver(CurrentService);
1457 }
1458 ServiceEntry = ServiceEntry->Flink;
1459 }
1460 }
1461
1462 /* Load all drivers without a tag or with an invalid tag */
1463 ServiceEntry = ServiceListHead.Flink;
1464 while (ServiceEntry != &ServiceListHead)
1465 {
1466 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1467 if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
1468 &CurrentService->ServiceGroup, TRUE) == 0) &&
1469 (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
1470 {
1471 for (i = 0; i < CurrentGroup->TagCount; i++)
1472 {
1473 if (CurrentGroup->TagArray[i] == CurrentService->Tag)
1474 {
1475 break;
1476 }
1477 }
1478 if (i >= CurrentGroup->TagCount)
1479 {
1480 DPRINT(" Path: %wZ\n", &CurrentService->RegistryPath);
1481 Status = IopLoadDriver(CurrentService);
1482 }
1483 }
1484 ServiceEntry = ServiceEntry->Flink;
1485 }
1486
1487 GroupEntry = GroupEntry->Flink;
1488 }
1489
1490 DPRINT("IopInitializeSystemDrivers() done\n");
1491 }
1492
1493 /*
1494 * IopUnloadDriver
1495 *
1496 * Unloads a device driver.
1497 *
1498 * Parameters
1499 * DriverServiceName
1500 * Name of the service to unload (registry key).
1501 *
1502 * UnloadPnpDrivers
1503 * Whether to unload Plug & Plug or only legacy drivers. If this
1504 * parameter is set to FALSE, the routine will unload only legacy
1505 * drivers.
1506 *
1507 * Return Value
1508 * Status
1509 *
1510 * To do
1511 * Guard the whole function by SEH.
1512 */
1513
1514 NTSTATUS STDCALL
1515 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
1516 {
1517 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1518 UNICODE_STRING ImagePath;
1519 UNICODE_STRING ServiceName;
1520 UNICODE_STRING ObjectName;
1521 PDRIVER_OBJECT DriverObject;
1522 PLDR_DATA_TABLE_ENTRY ModuleObject;
1523 NTSTATUS Status;
1524 LPWSTR Start;
1525
1526 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
1527
1528 PAGED_CODE();
1529
1530 /*
1531 * Get the service name from the registry key name
1532 */
1533
1534 Start = wcsrchr(DriverServiceName->Buffer, L'\\');
1535 if (Start == NULL)
1536 Start = DriverServiceName->Buffer;
1537 else
1538 Start++;
1539
1540 RtlInitUnicodeString(&ServiceName, Start);
1541
1542 /*
1543 * Construct the driver object name
1544 */
1545
1546 ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
1547 ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
1548 ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
1549 wcscpy(ObjectName.Buffer, L"\\Driver\\");
1550 memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
1551 ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
1552
1553 /*
1554 * Find the driver object
1555 */
1556
1557 Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
1558 KernelMode, 0, (PVOID*)&DriverObject);
1559
1560 if (!NT_SUCCESS(Status))
1561 {
1562 DPRINT("Can't locate driver object for %wZ\n", ObjectName);
1563 return Status;
1564 }
1565
1566 /*
1567 * Free the buffer for driver object name
1568 */
1569
1570 ExFreePool(ObjectName.Buffer);
1571
1572 /*
1573 * Get path of service...
1574 */
1575
1576 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1577
1578 RtlInitUnicodeString(&ImagePath, NULL);
1579
1580 QueryTable[0].Name = L"ImagePath";
1581 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1582 QueryTable[0].EntryContext = &ImagePath;
1583
1584 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1585 DriverServiceName->Buffer, QueryTable, NULL, NULL);
1586
1587 if (!NT_SUCCESS(Status))
1588 {
1589 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1590 return Status;
1591 }
1592
1593 /*
1594 * Normalize the image path for all later processing.
1595 */
1596
1597 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1598
1599 if (!NT_SUCCESS(Status))
1600 {
1601 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1602 return Status;
1603 }
1604
1605 /*
1606 * ... and check if it's loaded
1607 */
1608
1609 ModuleObject = LdrGetModuleObject(&ImagePath);
1610 if (ModuleObject == NULL)
1611 {
1612 return STATUS_UNSUCCESSFUL;
1613 }
1614
1615 /*
1616 * Free the service path
1617 */
1618
1619 ExFreePool(ImagePath.Buffer);
1620
1621 /*
1622 * Unload the module and release the references to the device object
1623 */
1624
1625 if (DriverObject->DriverUnload)
1626 (*DriverObject->DriverUnload)(DriverObject);
1627 ObDereferenceObject(DriverObject);
1628 ObDereferenceObject(DriverObject);
1629 LdrUnloadModule(ModuleObject);
1630
1631 return STATUS_SUCCESS;
1632 }
1633
1634 VOID FASTCALL
1635 IopMarkLastReinitializeDriver(VOID)
1636 {
1637 KIRQL Irql;
1638
1639 KeAcquireSpinLock(&DriverReinitListLock,
1640 &Irql);
1641
1642 if (IsListEmpty(&DriverReinitListHead))
1643 {
1644 DriverReinitTailEntry = NULL;
1645 }
1646 else
1647 {
1648 DriverReinitTailEntry = DriverReinitListHead.Blink;
1649 }
1650
1651 KeReleaseSpinLock(&DriverReinitListLock,
1652 Irql);
1653 }
1654
1655
1656 VOID FASTCALL
1657 IopReinitializeDrivers(VOID)
1658 {
1659 PDRIVER_REINIT_ITEM ReinitItem;
1660 PLIST_ENTRY Entry;
1661 KIRQL Irql;
1662
1663 KeAcquireSpinLock(&DriverReinitListLock,
1664 &Irql);
1665
1666 Entry = DriverReinitTailEntry;
1667
1668 KeReleaseSpinLock(&DriverReinitListLock,
1669 Irql);
1670
1671 if (Entry == NULL)
1672 {
1673 return;
1674 }
1675
1676 for (;;)
1677 {
1678 Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
1679 &DriverReinitListLock);
1680 if (Entry == NULL)
1681 return;
1682
1683 ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
1684
1685 /* Increment reinitialization counter */
1686 ReinitItem->DriverObject->DriverExtension->Count++;
1687
1688 ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
1689 ReinitItem->Context,
1690 ReinitItem->DriverObject->DriverExtension->Count);
1691
1692 ExFreePool(Entry);
1693
1694 if (Entry == DriverReinitTailEntry)
1695 return;
1696 }
1697 }
1698
1699 /* PUBLIC FUNCTIONS ***********************************************************/
1700
1701
1702 /*
1703 * @implemented
1704 */
1705 NTSTATUS
1706 STDCALL
1707 IoCreateDriver (
1708 IN PUNICODE_STRING DriverName, OPTIONAL
1709 IN PDRIVER_INITIALIZE InitializationFunction
1710 )
1711 {
1712 WCHAR NameBuffer[100];
1713 USHORT NameLength;
1714 UNICODE_STRING LocalDriverName; /* To reduce code if no name given */
1715 NTSTATUS Status;
1716 OBJECT_ATTRIBUTES ObjectAttributes;
1717 ULONG ObjectSize;
1718 PDRIVER_OBJECT DriverObject;
1719 UNICODE_STRING ServiceKeyName;
1720 HANDLE hDriver;
1721 ULONG i;
1722
1723 /* First, create a unique name for the driver if we don't have one */
1724 if (!DriverName) {
1725
1726 /* Create a random name and set up the string*/
1727 NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
1728 LocalDriverName.Length = NameLength * sizeof(WCHAR);
1729 LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
1730 LocalDriverName.Buffer = NameBuffer;
1731
1732 } else {
1733
1734 /* So we can avoid another code path, use a local var */
1735 LocalDriverName = *DriverName;
1736 }
1737
1738 /* Initialize the Attributes */
1739 ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION);
1740 InitializeObjectAttributes(&ObjectAttributes,
1741 &LocalDriverName,
1742 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
1743 NULL,
1744 NULL);
1745
1746 /* Create the Object */
1747 Status = ObCreateObject(KernelMode,
1748 IoDriverObjectType,
1749 &ObjectAttributes,
1750 KernelMode,
1751 NULL,
1752 ObjectSize,
1753 0,
1754 0,
1755 (PVOID*)&DriverObject);
1756
1757 /* Return on failure */
1758 if (!NT_SUCCESS(Status)) return Status;
1759
1760 /* Set up the Object */
1761 RtlZeroMemory(DriverObject, ObjectSize);
1762 DriverObject->Type = IO_TYPE_DRIVER;
1763 DriverObject->Size = sizeof(DRIVER_OBJECT);
1764 DriverObject->Flags = DRVO_BUILTIN_DRIVER;
1765 DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
1766 DriverObject->DriverExtension->DriverObject = DriverObject;
1767 DriverObject->DriverInit = InitializationFunction;
1768
1769 /* Invalidate all Major Functions */
1770 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
1771 {
1772 DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
1773 }
1774
1775 /* Set up the Service Key Name */
1776 ServiceKeyName.Buffer = ExAllocatePool(PagedPool, LocalDriverName.Length + sizeof(WCHAR));
1777 ServiceKeyName.Length = LocalDriverName.Length;
1778 ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
1779 RtlMoveMemory(ServiceKeyName.Buffer, LocalDriverName.Buffer, LocalDriverName.Length);
1780 ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = L'\0';
1781 DriverObject->DriverExtension->ServiceKeyName = ServiceKeyName;
1782
1783 /* Also store it in the Driver Object. This is a bit of a hack. */
1784 RtlMoveMemory(&DriverObject->DriverName, &ServiceKeyName, sizeof(UNICODE_STRING));
1785
1786 /* Add the Object and get its handle */
1787 Status = ObInsertObject(DriverObject,
1788 NULL,
1789 FILE_READ_DATA,
1790 0,
1791 NULL,
1792 &hDriver);
1793
1794 /* Return on Failure */
1795 if (!NT_SUCCESS(Status)) return Status;
1796
1797 /* Now reference it */
1798 Status = ObReferenceObjectByHandle(hDriver,
1799 0,
1800 IoDriverObjectType,
1801 KernelMode,
1802 (PVOID*)&DriverObject,
1803 NULL);
1804 ZwClose(hDriver);
1805
1806 /* Finally, call its init function */
1807 Status = (*InitializationFunction)(DriverObject, NULL);
1808
1809 if (!NT_SUCCESS(Status)) {
1810 /* If it didn't work, then kill the object */
1811 ObMakeTemporaryObject(DriverObject);
1812 ObDereferenceObject(DriverObject);
1813 }
1814
1815 /* Return the Status */
1816 return Status;
1817 }
1818
1819 /*
1820 * @implemented
1821 */
1822 VOID
1823 STDCALL
1824 IoDeleteDriver (
1825 IN PDRIVER_OBJECT DriverObject
1826 )
1827 {
1828 /* Simply derefence the Object */
1829 ObDereferenceObject(DriverObject);
1830 }
1831
1832
1833 /*
1834 * NtLoadDriver
1835 *
1836 * Loads a device driver.
1837 *
1838 * Parameters
1839 * DriverServiceName
1840 * Name of the service to load (registry key).
1841 *
1842 * Return Value
1843 * Status
1844 *
1845 * Status
1846 * implemented
1847 */
1848
1849 NTSTATUS STDCALL
1850 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
1851 {
1852 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
1853 UNICODE_STRING ImagePath;
1854 UNICODE_STRING ServiceName;
1855 UNICODE_STRING CapturedDriverServiceName;
1856 KPROCESSOR_MODE PreviousMode;
1857 NTSTATUS Status;
1858 ULONG Type;
1859 PDEVICE_NODE DeviceNode;
1860 PLDR_DATA_TABLE_ENTRY ModuleObject;
1861 PDRIVER_OBJECT DriverObject;
1862 WCHAR *cur;
1863
1864 PAGED_CODE();
1865
1866 PreviousMode = KeGetPreviousMode();
1867
1868 /*
1869 * Check security privileges
1870 */
1871
1872 /* FIXME: Uncomment when privileges will be correctly implemented. */
1873 #if 0
1874 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
1875 {
1876 DPRINT("Privilege not held\n");
1877 return STATUS_PRIVILEGE_NOT_HELD;
1878 }
1879 #endif
1880
1881 Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
1882 PreviousMode,
1883 DriverServiceName);
1884 if (!NT_SUCCESS(Status))
1885 {
1886 return Status;
1887 }
1888
1889 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
1890
1891 RtlInitUnicodeString(&ImagePath, NULL);
1892
1893 /*
1894 * Get the service name from the registry key name.
1895 */
1896 ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
1897
1898 ServiceName = CapturedDriverServiceName;
1899 cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
1900 while (CapturedDriverServiceName.Buffer != cur)
1901 {
1902 if(*cur == L'\\')
1903 {
1904 ServiceName.Buffer = cur + 1;
1905 ServiceName.Length = CapturedDriverServiceName.Length -
1906 (USHORT)((ULONG_PTR)ServiceName.Buffer -
1907 (ULONG_PTR)CapturedDriverServiceName.Buffer);
1908 break;
1909 }
1910 cur--;
1911 }
1912
1913 /*
1914 * Get service type.
1915 */
1916
1917 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
1918
1919 RtlInitUnicodeString(&ImagePath, NULL);
1920
1921 QueryTable[0].Name = L"Type";
1922 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1923 QueryTable[0].EntryContext = &Type;
1924
1925 QueryTable[1].Name = L"ImagePath";
1926 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
1927 QueryTable[1].EntryContext = &ImagePath;
1928
1929 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1930 CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
1931
1932 if (!NT_SUCCESS(Status))
1933 {
1934 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
1935 ExFreePool(ImagePath.Buffer);
1936 goto ReleaseCapturedString;
1937 }
1938
1939 /*
1940 * Normalize the image path for all later processing.
1941 */
1942
1943 Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
1944
1945 if (!NT_SUCCESS(Status))
1946 {
1947 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
1948 goto ReleaseCapturedString;
1949 }
1950
1951 DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
1952 DPRINT("Type: %lx\n", Type);
1953
1954 /*
1955 * See, if the driver module isn't already loaded
1956 */
1957
1958 ModuleObject = LdrGetModuleObject(&ImagePath);
1959 if (ModuleObject != NULL)
1960 {
1961 DPRINT("Image already loaded\n");
1962 Status = STATUS_IMAGE_ALREADY_LOADED;
1963 goto ReleaseCapturedString;
1964 }
1965
1966 /*
1967 * Create device node
1968 */
1969
1970 /* Use IopRootDeviceNode for now */
1971 Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
1972
1973 if (!NT_SUCCESS(Status))
1974 {
1975 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
1976 goto ReleaseCapturedString;
1977 }
1978
1979 /*
1980 * Load the driver module
1981 */
1982
1983 Status = LdrLoadModule(&ImagePath, &ModuleObject);
1984
1985 if (!NT_SUCCESS(Status))
1986 {
1987 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status);
1988 IopFreeDeviceNode(DeviceNode);
1989 goto ReleaseCapturedString;
1990 }
1991
1992 /*
1993 * Set a service name for the device node
1994 */
1995
1996 RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
1997
1998 /*
1999 * Initialize the driver module
2000 */
2001
2002 Status = IopInitializeDriverModule(
2003 DeviceNode,
2004 ModuleObject,
2005 &DeviceNode->ServiceName,
2006 (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2007 Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
2008 &DriverObject);
2009
2010 if (!NT_SUCCESS(Status))
2011 {
2012 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
2013 LdrUnloadModule(ModuleObject);
2014 IopFreeDeviceNode(DeviceNode);
2015 goto ReleaseCapturedString;
2016 }
2017
2018 IopInitializeDevice(DeviceNode, DriverObject);
2019 Status = IopStartDevice(DeviceNode);
2020
2021 ReleaseCapturedString:
2022 ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
2023 PreviousMode);
2024
2025 return Status;
2026 }
2027
2028 /*
2029 * NtUnloadDriver
2030 *
2031 * Unloads a legacy device driver.
2032 *
2033 * Parameters
2034 * DriverServiceName
2035 * Name of the service to unload (registry key).
2036 *
2037 * Return Value
2038 * Status
2039 *
2040 * Status
2041 * implemented
2042 */
2043
2044 NTSTATUS STDCALL
2045 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
2046 {
2047 return IopUnloadDriver(DriverServiceName, FALSE);
2048 }
2049
2050 /*
2051 * IoRegisterDriverReinitialization
2052 *
2053 * Status
2054 * @implemented
2055 */
2056
2057 VOID STDCALL
2058 IoRegisterDriverReinitialization(
2059 PDRIVER_OBJECT DriverObject,
2060 PDRIVER_REINITIALIZE ReinitRoutine,
2061 PVOID Context)
2062 {
2063 PDRIVER_REINIT_ITEM ReinitItem;
2064
2065 ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
2066 if (ReinitItem == NULL)
2067 return;
2068
2069 ReinitItem->DriverObject = DriverObject;
2070 ReinitItem->ReinitRoutine = ReinitRoutine;
2071 ReinitItem->Context = Context;
2072
2073 DriverObject->Flags |= DRVO_REINIT_REGISTERED;
2074
2075 ExInterlockedInsertTailList(
2076 &DriverReinitListHead,
2077 &ReinitItem->ItemEntry,
2078 &DriverReinitListLock);
2079 }
2080
2081 /*
2082 * @implemented
2083 */
2084 VOID
2085 STDCALL
2086 IoRegisterBootDriverReinitialization(
2087 IN PDRIVER_OBJECT DriverObject,
2088 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
2089 IN PVOID Context
2090 )
2091 {
2092 PDRIVER_REINIT_ITEM ReinitItem;
2093
2094 ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
2095 if (ReinitItem == NULL)
2096 return;
2097
2098 ReinitItem->DriverObject = DriverObject;
2099 ReinitItem->ReinitRoutine = DriverReinitializationRoutine;
2100 ReinitItem->Context = Context;
2101
2102 DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
2103
2104 ExInterlockedInsertTailList(
2105 &DriverBootReinitListHead,
2106 &ReinitItem->ItemEntry,
2107 &DriverReinitListLock);
2108 }
2109
2110 /*
2111 * IoAllocateDriverObjectExtension
2112 *
2113 * Status
2114 * @implemented
2115 */
2116
2117 NTSTATUS STDCALL
2118 IoAllocateDriverObjectExtension(
2119 PDRIVER_OBJECT DriverObject,
2120 PVOID ClientIdentificationAddress,
2121 ULONG DriverObjectExtensionSize,
2122 PVOID *DriverObjectExtension)
2123 {
2124 KIRQL OldIrql;
2125 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
2126 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension;
2127
2128 NewDriverExtension = ExAllocatePoolWithTag(
2129 NonPagedPool,
2130 sizeof(PRIVATE_DRIVER_EXTENSIONS) - sizeof(CHAR) +
2131 DriverObjectExtensionSize,
2132 TAG_DRIVER_EXTENSION);
2133
2134 if (NewDriverExtension == NULL)
2135 {
2136 return STATUS_INSUFFICIENT_RESOURCES;
2137 }
2138
2139 OldIrql = KeRaiseIrqlToDpcLevel();
2140
2141 NewDriverExtension->Link = DriverObject->DriverSection;
2142 NewDriverExtension->ClientIdentificationAddress = ClientIdentificationAddress;
2143
2144 for (DriverExtensions = DriverObject->DriverSection;
2145 DriverExtensions != NULL;
2146 DriverExtensions = DriverExtensions->Link)
2147 {
2148 if (DriverExtensions->ClientIdentificationAddress ==
2149 ClientIdentificationAddress)
2150 {
2151 KfLowerIrql(OldIrql);
2152 return STATUS_OBJECT_NAME_COLLISION;
2153 }
2154 }
2155
2156 DriverObject->DriverSection = NewDriverExtension;
2157
2158 KfLowerIrql(OldIrql);
2159
2160 *DriverObjectExtension = &NewDriverExtension->Extension;
2161
2162 return STATUS_SUCCESS;
2163 }
2164
2165 /*
2166 * IoGetDriverObjectExtension
2167 *
2168 * Status
2169 * @implemented
2170 */
2171
2172 PVOID STDCALL
2173 IoGetDriverObjectExtension(
2174 PDRIVER_OBJECT DriverObject,
2175 PVOID ClientIdentificationAddress)
2176 {
2177 KIRQL OldIrql;
2178 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions;
2179
2180 OldIrql = KeRaiseIrqlToDpcLevel();
2181
2182 for (DriverExtensions = DriverObject->DriverSection;
2183 DriverExtensions != NULL &&
2184 DriverExtensions->ClientIdentificationAddress !=
2185 ClientIdentificationAddress;
2186 DriverExtensions = DriverExtensions->Link)
2187 ;
2188
2189 KfLowerIrql(OldIrql);
2190
2191 if (DriverExtensions == NULL)
2192 return NULL;
2193
2194 return &DriverExtensions->Extension;
2195 }
2196
2197 /* EOF */