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
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 * Filip Navara (xnavara@volny.cz)
12 /* INCLUDES *******************************************************************/
16 #include <internal/debug.h>
19 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock
;
20 extern ULONG KeTickCount
;
21 extern BOOLEAN SetupMode
;
24 LdrProcessModule(PVOID ModuleLoadBase
,
25 PUNICODE_STRING ModuleName
,
26 PMODULE_OBJECT
*ModuleObject
);
28 typedef struct _SERVICE_GROUP
30 LIST_ENTRY GroupListEntry
;
31 UNICODE_STRING GroupName
;
32 BOOLEAN ServicesRunning
;
35 } SERVICE_GROUP
, *PSERVICE_GROUP
;
37 typedef struct _SERVICE
39 LIST_ENTRY ServiceListEntry
;
40 UNICODE_STRING ServiceName
;
41 UNICODE_STRING RegistryPath
;
42 UNICODE_STRING ServiceGroup
;
43 UNICODE_STRING ImagePath
;
50 /* BOOLEAN ServiceRunning;*/ // needed ??
53 typedef struct _DRIVER_REINIT_ITEM
56 PDRIVER_OBJECT DriverObject
;
57 PDRIVER_REINITIALIZE ReinitRoutine
;
59 } DRIVER_REINIT_ITEM
, *PDRIVER_REINIT_ITEM
;
61 /* GLOBALS ********************************************************************/
63 static LIST_ENTRY DriverReinitListHead
;
64 static KSPIN_LOCK DriverReinitListLock
;
65 static PLIST_ENTRY DriverReinitTailEntry
;
67 static PLIST_ENTRY DriverBootReinitTailEntry
;
68 static LIST_ENTRY DriverBootReinitListHead
;
69 static KSPIN_LOCK DriverBootReinitListLock
;
71 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
72 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
74 static UNICODE_STRING IopHardwareDatabaseKey
=
75 ROS_STRING_INITIALIZER(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
77 POBJECT_TYPE EXPORTED IoDriverObjectType
= NULL
;
79 /* DECLARATIONS ***************************************************************/
82 IopDeleteDriver(PVOID ObjectBody
);
84 /* PRIVATE FUNCTIONS **********************************************************/
88 IopInitDriverImplementation(VOID
)
90 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
93 DPRINT("Creating Registry Object Type\n");
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
;
104 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoDriverObjectType
);
106 InitializeListHead(&DriverReinitListHead
);
107 KeInitializeSpinLock(&DriverReinitListLock
);
108 DriverReinitTailEntry
= NULL
;
110 InitializeListHead(&DriverBootReinitListHead
);
111 KeInitializeSpinLock(&DriverBootReinitListLock
);
112 DriverBootReinitTailEntry
= NULL
;
116 IopInvalidDeviceRequest(
117 PDEVICE_OBJECT DeviceObject
,
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
;
127 IopDeleteDriver(PVOID ObjectBody
)
129 PDRIVER_OBJECT Object
= ObjectBody
;
131 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
133 DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody
);
135 ExFreePool(Object
->DriverExtension
);
136 ExFreePool(Object
->DriverName
.Buffer
);
138 OldIrql
= KeRaiseIrqlToDpcLevel();
140 for (DriverExtension
= Object
->DriverSection
;
141 DriverExtension
!= NULL
;
142 DriverExtension
= NextDriverExtension
)
144 NextDriverExtension
= DriverExtension
->Link
;
145 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
148 KfLowerIrql(OldIrql
);
153 PDRIVER_OBJECT
*DriverObject
,
154 PUNICODE_STRING ServiceName
,
157 PDRIVER_OBJECT Object
;
158 WCHAR NameBuffer
[MAX_PATH
];
159 UNICODE_STRING DriverName
;
160 OBJECT_ATTRIBUTES ObjectAttributes
;
163 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
164 DriverObject
, ServiceName
, FileSystem
);
166 *DriverObject
= NULL
;
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
;
173 if (FileSystem
== TRUE
)
174 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
176 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
177 wcscat(NameBuffer
, ServiceName
->Buffer
);
179 RtlInitUnicodeString(&DriverName
, NameBuffer
);
180 DPRINT("Driver name: '%wZ'\n", &DriverName
);
182 /* Initialize ObjectAttributes for driver object */
183 InitializeObjectAttributes(
186 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
190 /* Open driver object */
191 Status
= ObReferenceObjectByName(
194 NULL
, /* PassedAccessState */
195 0, /* DesiredAccess */
198 NULL
, /* ParseContext */
201 if (!NT_SUCCESS(Status
))
204 *DriverObject
= Object
;
206 return STATUS_SUCCESS
;
210 IopCreateDriverObject(
211 PDRIVER_OBJECT
*DriverObject
,
212 PUNICODE_STRING ServiceName
,
213 ULONG CreateAttributes
,
215 PVOID DriverImageStart
,
216 ULONG DriverImageSize
)
218 PDRIVER_OBJECT Object
;
219 WCHAR NameBuffer
[MAX_PATH
];
220 UNICODE_STRING DriverName
;
221 OBJECT_ATTRIBUTES ObjectAttributes
;
226 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
227 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
229 *DriverObject
= NULL
;
231 /* Create ModuleName string */
232 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
234 if (FileSystem
== TRUE
)
235 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
237 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
238 wcscat(NameBuffer
, ServiceName
->Buffer
);
240 RtlInitUnicodeString(&DriverName
, NameBuffer
);
241 DPRINT("Driver name: '%wZ'\n", &DriverName
);
243 Buffer
= (PWSTR
)ExAllocatePool(NonPagedPool
, DriverName
.Length
);
244 /* If we don't success, it is not a problem. Our driver
245 * object will not have associated driver name... */
249 RtlInitUnicodeString(&DriverName
, NULL
);
252 /* Initialize ObjectAttributes for driver object */
253 InitializeObjectAttributes(
256 CreateAttributes
| OBJ_PERMANENT
,
260 /* Create driver object */
261 Status
= ObCreateObject(
267 sizeof(DRIVER_OBJECT
),
272 if (!NT_SUCCESS(Status
))
277 Status
= ObInsertObject(Object
,
283 if (!NT_SUCCESS(Status
))
288 /* Create driver extension */
289 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
290 ExAllocatePoolWithTag(
292 sizeof(DRIVER_EXTENSION
),
293 TAG_DRIVER_EXTENSION
);
295 if (Object
->DriverExtension
== NULL
)
297 return STATUS_NO_MEMORY
;
300 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
302 Object
->Type
= IO_TYPE_DRIVER
;
304 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
305 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
307 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
309 Object
->DriverStart
= DriverImageStart
;
310 Object
->DriverSize
= DriverImageSize
;
313 if (!Object
->DriverName
.Buffer
)
315 Object
->DriverName
.Buffer
= Buffer
;
316 Object
->DriverName
.Length
= Object
->DriverName
.MaximumLength
= DriverName
.Length
;
317 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
323 *DriverObject
= Object
;
325 return STATUS_SUCCESS
;
329 * IopDisplayLoadingMessage
331 * Display 'Loading XXX...' message.
337 IopDisplayLoadingMessage(PVOID ServiceName
,
340 if (SetupMode
) return;
341 CHAR TextBuffer
[256];
344 sprintf(TextBuffer
, "Loading %S...\n", (PWCHAR
)ServiceName
);
348 sprintf(TextBuffer
, "Loading %s...\n", (PCHAR
)ServiceName
);
350 HalDisplayString(TextBuffer
);
354 * IopNormalizeImagePath
356 * Normalize an image path to contain complete path.
360 * The input path and on exit the result path. ImagePath.Buffer
361 * must be allocated by ExAllocatePool on input. Caller is responsible
362 * for freeing the buffer when it's no longer needed.
365 * Name of the service that ImagePath belongs to.
371 * The input image path isn't freed on error.
375 IopNormalizeImagePath(
376 IN OUT PUNICODE_STRING ImagePath
,
377 IN PUNICODE_STRING ServiceName
)
379 UNICODE_STRING InputImagePath
;
384 sizeof(UNICODE_STRING
));
386 if (InputImagePath
.Length
== 0)
388 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
389 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
390 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
391 if (ImagePath
->Buffer
== NULL
)
392 return STATUS_NO_MEMORY
;
394 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
395 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
396 wcscat(ImagePath
->Buffer
, L
".sys");
398 if (InputImagePath
.Buffer
[0] != L
'\\')
400 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
401 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
402 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
403 if (ImagePath
->Buffer
== NULL
)
404 return STATUS_NO_MEMORY
;
406 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
407 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
408 ExFreePool(InputImagePath
.Buffer
);
411 return STATUS_SUCCESS
;
415 * IopLoadServiceModule
417 * Load a module specified by registry settings for service.
421 * Name of the service to load.
428 IopLoadServiceModule(
429 IN PUNICODE_STRING ServiceName
,
430 OUT PMODULE_OBJECT
*ModuleObject
)
432 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
434 UNICODE_STRING ServiceImagePath
;
437 DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName
, ModuleObject
);
440 * Get information about the service.
443 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
445 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
447 QueryTable
[0].Name
= L
"Start";
448 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
449 QueryTable
[0].EntryContext
= &ServiceStart
;
451 QueryTable
[1].Name
= L
"ImagePath";
452 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
453 QueryTable
[1].EntryContext
= &ServiceImagePath
;
455 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
456 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
458 if (!NT_SUCCESS(Status
))
460 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
464 IopDisplayLoadingMessage(ServiceName
->Buffer
, TRUE
);
467 * Normalize the image path for all later processing.
470 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
472 if (!NT_SUCCESS(Status
))
474 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
482 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
484 if (*ModuleObject
== NULL
)
486 Status
= STATUS_UNSUCCESSFUL
;
489 * Special case for boot modules that were loaded by boot loader.
492 if (ServiceStart
== 0)
495 CHAR SearchName
[256];
497 PLOADER_MODULE KeLoaderModules
=
498 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
502 * Improve this searching algorithm by using the image name
503 * stored in registry entry ImageName and use the whole path
504 * (requires change in FreeLoader).
507 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
508 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
510 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
511 if (!_stricmp(ModuleName
, SearchName
))
513 DPRINT("Initializing boot module\n");
515 /* Tell, that the module is already loaded */
516 KeLoaderModules
[i
].Reserved
= 1;
518 Status
= LdrProcessModule(
519 (PVOID
)KeLoaderModules
[i
].ModStart
,
523 KDB_SYMBOLFILE_HOOK(SearchName
);
531 * Case for rest of the drivers (except disabled)
534 else if (ServiceStart
< 4)
536 DPRINT("Loading module\n");
537 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
542 DPRINT("Module already loaded\n");
543 Status
= STATUS_IMAGE_ALREADY_LOADED
;
546 ExFreePool(ServiceImagePath
.Buffer
);
549 * Now check if the module was loaded successfully.
552 if (!NT_SUCCESS(Status
))
554 DPRINT("Module loading failed (Status %x)\n", Status
);
557 DPRINT("Module loading (Status %x)\n", Status
);
563 * IopInitializeDriverModule
565 * Initalize a loaded driver.
569 * Pointer to device node.
572 * Module object representing the driver. It can be retrieve by
573 * IopLoadServiceModule.
576 * Name of the service (as in registry).
579 * Set to TRUE for file system drivers.
582 * On successful return this contains the driver object representing
587 IopInitializeDriverModule(
588 IN PDEVICE_NODE DeviceNode
,
589 IN PMODULE_OBJECT ModuleObject
,
590 IN PUNICODE_STRING ServiceName
,
591 IN BOOLEAN FileSystemDriver
,
592 OUT PDRIVER_OBJECT
*DriverObject
)
594 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
595 UNICODE_STRING RegistryKey
;
596 PDRIVER_INITIALIZE DriverEntry
;
599 DriverEntry
= ModuleObject
->EntryPoint
;
601 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
603 RegistryKey
.Length
= 0;
604 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
605 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
606 if (RegistryKey
.Buffer
== NULL
)
608 return STATUS_INSUFFICIENT_RESOURCES
;
610 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
611 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
615 RtlInitUnicodeString(&RegistryKey
, NULL
);
618 Status
= IopCreateDriverObject(
624 ModuleObject
->Length
);
626 if (!NT_SUCCESS(Status
))
628 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
632 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
633 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
635 IopMarkLastReinitializeDriver();
637 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
639 RtlFreeUnicodeString(&RegistryKey
);
641 if (!NT_SUCCESS(Status
))
643 ObMakeTemporaryObject(*DriverObject
);
644 ObDereferenceObject(*DriverObject
);
648 IopReinitializeDrivers();
650 return STATUS_SUCCESS
;
654 * IopAttachFilterDriversCallback
656 * Internal routine used by IopAttachFilterDrivers.
660 IopAttachFilterDriversCallback(
668 PDEVICE_NODE DeviceNode
= Context
;
669 UNICODE_STRING ServiceName
;
671 PMODULE_OBJECT ModuleObject
;
672 PDRIVER_OBJECT DriverObject
;
675 for (Filters
= ValueData
;
676 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
678 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
680 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
681 ServiceName
.Buffer
= Filters
;
682 ServiceName
.MaximumLength
=
683 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
685 /* Load and initialize the filter driver */
686 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
687 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
689 if (!NT_SUCCESS(Status
))
692 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
693 FALSE
, &DriverObject
);
694 if (!NT_SUCCESS(Status
))
699 /* get existing DriverObject pointer */
700 Status
= IopGetDriverObject(
704 if (!NT_SUCCESS(Status
))
708 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
709 if (!NT_SUCCESS(Status
))
713 return STATUS_SUCCESS
;
717 * IopAttachFilterDrivers
719 * Load filter drivers for specified device node.
723 * Set to TRUE for loading lower level filters or FALSE for upper
728 IopAttachFilterDrivers(
729 PDEVICE_NODE DeviceNode
,
732 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
734 UNICODE_STRING Class
;
735 WCHAR ClassBuffer
[40];
739 * First load the device filters
742 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
744 QueryTable
[0].Name
= L
"LowerFilters";
746 QueryTable
[0].Name
= L
"UpperFilters";
747 QueryTable
[0].EntryContext
= NULL
;
748 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
749 QueryTable
[1].QueryRoutine
= NULL
;
750 QueryTable
[1].Name
= NULL
;
752 KeyBuffer
= ExAllocatePool(
754 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
755 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
756 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
758 RtlQueryRegistryValues(
759 RTL_REGISTRY_ABSOLUTE
,
766 * Now get the class GUID
770 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
771 Class
.Buffer
= ClassBuffer
;
772 QueryTable
[0].QueryRoutine
= NULL
;
773 QueryTable
[0].Name
= L
"ClassGUID";
774 QueryTable
[0].EntryContext
= &Class
;
775 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
777 Status
= RtlQueryRegistryValues(
778 RTL_REGISTRY_ABSOLUTE
,
784 ExFreePool(KeyBuffer
);
787 * Load the class filter driver
790 if (NT_SUCCESS(Status
))
792 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
794 QueryTable
[0].Name
= L
"LowerFilters";
796 QueryTable
[0].Name
= L
"UpperFilters";
797 QueryTable
[0].EntryContext
= NULL
;
798 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
800 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
801 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
802 wcscat(KeyBuffer
, ClassBuffer
);
804 RtlQueryRegistryValues(
805 RTL_REGISTRY_ABSOLUTE
,
811 ExFreePool(KeyBuffer
);
814 return STATUS_SUCCESS
;
817 static NTSTATUS STDCALL
818 IopGetGroupOrderList(PWSTR ValueName
,
825 PSERVICE_GROUP Group
;
827 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
828 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
830 if (ValueType
== REG_BINARY
&&
832 ValueLength
>= sizeof(DWORD
) &&
833 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
835 Group
= (PSERVICE_GROUP
)Context
;
836 Group
->TagCount
= ((PULONG
)ValueData
)[0];
837 if (Group
->TagCount
> 0)
839 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
841 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
842 if (Group
->TagArray
== NULL
)
845 return STATUS_INSUFFICIENT_RESOURCES
;
847 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
852 return STATUS_UNSUCCESSFUL
;
856 return STATUS_SUCCESS
;
859 static NTSTATUS STDCALL
860 IopCreateGroupListEntry(PWSTR ValueName
,
867 PSERVICE_GROUP Group
;
868 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
872 if (ValueType
== REG_SZ
)
874 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
876 Group
= ExAllocatePool(NonPagedPool
,
877 sizeof(SERVICE_GROUP
));
880 return(STATUS_INSUFFICIENT_RESOURCES
);
883 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
885 if (!RtlpCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
, NonPagedPool
))
888 return(STATUS_INSUFFICIENT_RESOURCES
);
891 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
892 QueryTable
[0].Name
= (PWSTR
)ValueData
;
893 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
895 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
900 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
902 InsertTailList(&GroupListHead
,
903 &Group
->GroupListEntry
);
906 return(STATUS_SUCCESS
);
910 static NTSTATUS STDCALL
911 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
913 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
917 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
919 /* Allocate service entry */
920 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
923 DPRINT1("ExAllocatePool() failed\n");
924 return(STATUS_INSUFFICIENT_RESOURCES
);
926 RtlZeroMemory(Service
, sizeof(SERVICE
));
928 /* Get service data */
929 RtlZeroMemory(&QueryTable
,
932 QueryTable
[0].Name
= L
"Start";
933 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
934 QueryTable
[0].EntryContext
= &Service
->Start
;
936 QueryTable
[1].Name
= L
"Type";
937 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
938 QueryTable
[1].EntryContext
= &Service
->Type
;
940 QueryTable
[2].Name
= L
"ErrorControl";
941 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
942 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
944 QueryTable
[3].Name
= L
"Group";
945 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
946 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
948 QueryTable
[4].Name
= L
"ImagePath";
949 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
950 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
952 QueryTable
[5].Name
= L
"Tag";
953 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
954 QueryTable
[5].EntryContext
= &Service
->Tag
;
956 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
961 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
964 * If something goes wrong during RtlQueryRegistryValues
965 * it'll just drop everything on the floor and return,
966 * so you have to check if the buffers were filled.
967 * Luckily we zerofilled the Service.
969 if (Service
->ServiceGroup
.Buffer
)
971 ExFreePool(Service
->ServiceGroup
.Buffer
);
973 if (Service
->ImagePath
.Buffer
)
975 ExFreePool(Service
->ImagePath
.Buffer
);
981 /* Copy service name */
982 Service
->ServiceName
.Length
= ServiceName
->Length
;
983 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
984 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
985 Service
->ServiceName
.MaximumLength
);
986 RtlCopyMemory(Service
->ServiceName
.Buffer
,
988 ServiceName
->Length
);
989 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
991 /* Build registry path */
992 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
993 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
994 MAX_PATH
* sizeof(WCHAR
));
995 wcscpy(Service
->RegistryPath
.Buffer
,
996 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
997 wcscat(Service
->RegistryPath
.Buffer
,
998 Service
->ServiceName
.Buffer
);
999 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
1001 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
1002 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
1003 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
1004 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
1005 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1006 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
1008 /* Append service entry */
1009 InsertTailList(&ServiceListHead
,
1010 &Service
->ServiceListEntry
);
1012 return(STATUS_SUCCESS
);
1016 NTSTATUS INIT_FUNCTION
1017 IoCreateDriverList(VOID
)
1019 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1020 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
1021 OBJECT_ATTRIBUTES ObjectAttributes
;
1022 UNICODE_STRING ServicesKeyName
;
1023 UNICODE_STRING SubKeyName
;
1028 ULONG KeyInfoLength
= 0;
1029 ULONG ReturnedLength
;
1031 DPRINT("IoCreateDriverList() called\n");
1033 /* Initialize basic variables */
1034 InitializeListHead(&GroupListHead
);
1035 InitializeListHead(&ServiceListHead
);
1037 /* Build group order list */
1038 RtlZeroMemory(&QueryTable
,
1039 sizeof(QueryTable
));
1041 QueryTable
[0].Name
= L
"List";
1042 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1044 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1045 L
"ServiceGroupOrder",
1049 if (!NT_SUCCESS(Status
))
1052 /* Enumerate services and create the service list */
1053 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
1054 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1056 InitializeObjectAttributes(&ObjectAttributes
,
1058 OBJ_CASE_INSENSITIVE
,
1062 Status
= ZwOpenKey(&KeyHandle
,
1063 KEY_ENUMERATE_SUB_KEYS
,
1065 if (!NT_SUCCESS(Status
))
1070 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1071 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1072 if (KeyInfo
== NULL
)
1075 return(STATUS_INSUFFICIENT_RESOURCES
);
1081 Status
= ZwEnumerateKey(KeyHandle
,
1083 KeyBasicInformation
,
1087 if (NT_SUCCESS(Status
))
1089 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1092 SubKeyName
.Length
= KeyInfo
->NameLength
;
1093 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1094 SubKeyName
.Buffer
= KeyInfo
->Name
;
1095 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1097 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1098 IopCreateServiceListEntry(&SubKeyName
);
1102 if (!NT_SUCCESS(Status
))
1108 ExFreePool(KeyInfo
);
1111 DPRINT("IoCreateDriverList() done\n");
1113 return(STATUS_SUCCESS
);
1116 NTSTATUS INIT_FUNCTION
1117 IoDestroyDriverList(VOID
)
1119 PLIST_ENTRY GroupEntry
;
1120 PLIST_ENTRY ServiceEntry
;
1121 PSERVICE_GROUP CurrentGroup
;
1122 PSERVICE CurrentService
;
1124 DPRINT("IoDestroyDriverList() called\n");
1126 /* Destroy group list */
1127 GroupEntry
= GroupListHead
.Flink
;
1128 while (GroupEntry
!= &GroupListHead
)
1130 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1132 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1133 RemoveEntryList(GroupEntry
);
1134 if (CurrentGroup
->TagArray
)
1136 ExFreePool(CurrentGroup
->TagArray
);
1138 ExFreePool(CurrentGroup
);
1140 GroupEntry
= GroupListHead
.Flink
;
1143 /* Destroy service list */
1144 ServiceEntry
= ServiceListHead
.Flink
;
1145 while (ServiceEntry
!= &ServiceListHead
)
1147 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1149 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1150 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1151 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1152 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1153 RemoveEntryList(ServiceEntry
);
1154 ExFreePool(CurrentService
);
1156 ServiceEntry
= ServiceListHead
.Flink
;
1159 DPRINT("IoDestroyDriverList() done\n");
1161 return(STATUS_SUCCESS
);
1164 VOID STATIC INIT_FUNCTION
1165 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1169 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1171 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1176 * IopInitializeBuiltinDriver
1178 * Initialize a driver that is already loaded in memory.
1181 NTSTATUS FASTCALL INIT_FUNCTION
1182 IopInitializeBuiltinDriver(
1183 PDEVICE_NODE ModuleDeviceNode
,
1184 PVOID ModuleLoadBase
,
1188 PMODULE_OBJECT ModuleObject
;
1189 PDEVICE_NODE DeviceNode
;
1190 PDRIVER_OBJECT DriverObject
;
1192 PCHAR FileNameWithoutPath
;
1193 LPWSTR FileExtension
;
1195 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1196 FileName
, ModuleLoadBase
, ModuleLength
);
1199 * Display 'Loading XXX...' message
1201 IopDisplayLoadingMessage(FileName
, FALSE
);
1204 * Determine the right device object
1207 if (ModuleDeviceNode
== NULL
)
1209 /* Use IopRootDeviceNode for now */
1210 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1211 if (!NT_SUCCESS(Status
))
1213 CPRINT("Driver load failed, status (%x)\n", Status
);
1218 DeviceNode
= ModuleDeviceNode
;
1222 * Generate filename without path (not needed by freeldr)
1225 FileNameWithoutPath
= strrchr(FileName
, '\\');
1226 if (FileNameWithoutPath
== NULL
)
1228 FileNameWithoutPath
= FileName
;
1235 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1236 FileNameWithoutPath
);
1237 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1239 if (!NT_SUCCESS(Status
))
1241 if (ModuleDeviceNode
== NULL
)
1242 IopFreeDeviceNode(DeviceNode
);
1243 CPRINT("Driver load failed, status (%x)\n", Status
);
1248 KDB_SYMBOLFILE_HOOK(FileName
);
1251 * Strip the file extension from ServiceName
1254 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1255 if (FileExtension
!= NULL
)
1257 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1258 FileExtension
[0] = 0;
1262 * Initialize the driver
1265 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1266 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1268 if (!NT_SUCCESS(Status
))
1270 if (ModuleDeviceNode
== NULL
)
1271 IopFreeDeviceNode(DeviceNode
);
1272 CPRINT("Driver load failed, status (%x)\n", Status
);
1276 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1277 if (NT_SUCCESS(Status
))
1279 Status
= IopStartDevice(DeviceNode
);
1286 * IopInitializeBootDrivers
1288 * Initialize boot drivers and free memory for boot files.
1298 IopInitializeBootDrivers(VOID
)
1300 ULONG BootDriverCount
;
1306 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1308 UNICODE_STRING DriverName
;
1311 DPRINT("IopInitializeBootDrivers()\n");
1313 BootDriverCount
= 0;
1314 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1316 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1317 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1318 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1319 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1320 Extension
= strrchr(ModuleName
, '.');
1321 if (Extension
== NULL
)
1324 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1326 /* Process symbols for *.exe and *.dll */
1327 KDB_SYMBOLFILE_HOOK(ModuleName
);
1329 /* Log *.exe and *.dll files */
1330 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1331 IopBootLog(&DriverName
, TRUE
);
1332 RtlFreeUnicodeString(&DriverName
);
1334 else if (!_stricmp(Extension
, ".sys"))
1336 /* Initialize and log boot start driver */
1339 Status
= IopInitializeBuiltinDriver(NULL
,
1343 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1344 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1345 RtlFreeUnicodeString(&DriverName
);
1352 * Free memory for all boot files, except ntoskrnl.exe.
1354 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1356 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1357 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1360 KeLoaderBlock
.ModsCount
= 0;
1362 if (BootDriverCount
== 0)
1364 DbgPrint("No boot drivers available.\n");
1369 static INIT_FUNCTION NTSTATUS
1370 IopLoadDriver(PSERVICE Service
)
1372 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1374 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1375 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1376 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1377 if (!NT_SUCCESS(Status
))
1379 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1381 if (Service
->ErrorControl
== 1)
1385 else if (Service
->ErrorControl
== 2)
1387 if (IsLastKnownGood
== FALSE
)
1389 /* Boot last known good configuration */
1392 else if (Service
->ErrorControl
== 3)
1394 if (IsLastKnownGood
== FALSE
)
1396 /* Boot last known good configuration */
1410 * IopInitializeSystemDrivers
1412 * Load drivers marked as system start.
1422 IopInitializeSystemDrivers(VOID
)
1424 PLIST_ENTRY GroupEntry
;
1425 PLIST_ENTRY ServiceEntry
;
1426 PSERVICE_GROUP CurrentGroup
;
1427 PSERVICE CurrentService
;
1431 DPRINT("IopInitializeSystemDrivers()\n");
1433 GroupEntry
= GroupListHead
.Flink
;
1434 while (GroupEntry
!= &GroupListHead
)
1436 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1438 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1440 /* Load all drivers with a valid tag */
1441 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1443 ServiceEntry
= ServiceListHead
.Flink
;
1444 while (ServiceEntry
!= &ServiceListHead
)
1446 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1448 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1449 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1450 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1451 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1453 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1454 Status
= IopLoadDriver(CurrentService
);
1456 ServiceEntry
= ServiceEntry
->Flink
;
1460 /* Load all drivers without a tag or with an invalid tag */
1461 ServiceEntry
= ServiceListHead
.Flink
;
1462 while (ServiceEntry
!= &ServiceListHead
)
1464 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1465 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1466 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1467 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1469 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1471 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1476 if (i
>= CurrentGroup
->TagCount
)
1478 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1479 Status
= IopLoadDriver(CurrentService
);
1482 ServiceEntry
= ServiceEntry
->Flink
;
1485 GroupEntry
= GroupEntry
->Flink
;
1488 DPRINT("IopInitializeSystemDrivers() done\n");
1494 * Unloads a device driver.
1498 * Name of the service to unload (registry key).
1501 * Whether to unload Plug & Plug or only legacy drivers. If this
1502 * parameter is set to FALSE, the routine will unload only legacy
1509 * Guard the whole function by SEH.
1513 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1515 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1516 UNICODE_STRING ImagePath
;
1517 UNICODE_STRING ServiceName
;
1518 UNICODE_STRING ObjectName
;
1519 PDRIVER_OBJECT DriverObject
;
1520 PMODULE_OBJECT ModuleObject
;
1524 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1527 * Get the service name from the registry key name
1530 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1532 Start
= DriverServiceName
->Buffer
;
1536 RtlInitUnicodeString(&ServiceName
, Start
);
1539 * Construct the driver object name
1542 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1543 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1544 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1545 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1546 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1547 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1550 * Find the driver object
1553 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1554 KernelMode
, 0, (PVOID
*)&DriverObject
);
1556 if (!NT_SUCCESS(Status
))
1558 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1563 * Free the buffer for driver object name
1566 ExFreePool(ObjectName
.Buffer
);
1569 * Get path of service...
1572 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1574 RtlInitUnicodeString(&ImagePath
, NULL
);
1576 QueryTable
[0].Name
= L
"ImagePath";
1577 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1578 QueryTable
[0].EntryContext
= &ImagePath
;
1580 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1581 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1583 if (!NT_SUCCESS(Status
))
1585 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1590 * Normalize the image path for all later processing.
1593 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1602 * ... and check if it's loaded
1605 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1606 if (ModuleObject
== NULL
)
1608 return STATUS_UNSUCCESSFUL
;
1612 * Free the service path
1615 ExFreePool(ImagePath
.Buffer
);
1618 * Unload the module and release the references to the device object
1621 if (DriverObject
->DriverUnload
)
1622 (*DriverObject
->DriverUnload
)(DriverObject
);
1623 ObDereferenceObject(DriverObject
);
1624 ObDereferenceObject(DriverObject
);
1625 LdrUnloadModule(ModuleObject
);
1627 return STATUS_SUCCESS
;
1631 IopMarkLastReinitializeDriver(VOID
)
1635 KeAcquireSpinLock(&DriverReinitListLock
,
1638 if (IsListEmpty(&DriverReinitListHead
))
1640 DriverReinitTailEntry
= NULL
;
1644 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1647 KeReleaseSpinLock(&DriverReinitListLock
,
1653 IopReinitializeDrivers(VOID
)
1655 PDRIVER_REINIT_ITEM ReinitItem
;
1659 KeAcquireSpinLock(&DriverReinitListLock
,
1662 if (DriverReinitTailEntry
== NULL
)
1664 KeReleaseSpinLock(&DriverReinitListLock
,
1669 KeReleaseSpinLock(&DriverReinitListLock
,
1674 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1675 &DriverReinitListLock
);
1679 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1681 /* Increment reinitialization counter */
1682 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1684 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1685 ReinitItem
->Context
,
1686 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1690 if (Entry
== DriverReinitTailEntry
)
1695 /* PUBLIC FUNCTIONS ***********************************************************/
1704 IN PUNICODE_STRING DriverName
, OPTIONAL
1705 IN PDRIVER_INITIALIZE InitializationFunction
1708 WCHAR NameBuffer
[100];
1710 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1712 OBJECT_ATTRIBUTES ObjectAttributes
;
1714 PDRIVER_OBJECT DriverObject
;
1715 UNICODE_STRING ServiceKeyName
;
1719 /* First, create a unique name for the driver if we don't have one */
1722 /* Create a random name and set up the string*/
1723 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1724 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1725 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1726 LocalDriverName
.Buffer
= NameBuffer
;
1730 /* So we can avoid another code path, use a local var */
1731 LocalDriverName
= *DriverName
;
1734 /* Initialize the Attributes */
1735 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1736 InitializeObjectAttributes(&ObjectAttributes
,
1738 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1742 /* Create the Object */
1743 Status
= ObCreateObject(KernelMode
,
1751 (PVOID
*)&DriverObject
);
1753 /* Return on failure */
1754 if (!NT_SUCCESS(Status
)) return Status
;
1756 /* Set up the Object */
1757 RtlZeroMemory(DriverObject
, ObjectSize
);
1758 DriverObject
->Type
= IO_TYPE_DRIVER
;
1759 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1760 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1761 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1762 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1763 DriverObject
->DriverInit
= InitializationFunction
;
1765 /* Invalidate all Major Functions */
1766 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1768 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1771 /* Set up the Service Key Name */
1772 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1773 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1774 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1775 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1776 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1777 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1779 /* Also store it in the Driver Object. This is a bit of a hack. */
1780 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1782 /* Add the Object and get its handle */
1783 Status
= ObInsertObject(DriverObject
,
1790 /* Return on Failure */
1791 if (!NT_SUCCESS(Status
)) return Status
;
1793 /* Now reference it */
1794 Status
= ObReferenceObjectByHandle(hDriver
,
1798 (PVOID
*)&DriverObject
,
1802 /* Finally, call its init function */
1803 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1805 if (!NT_SUCCESS(Status
)) {
1806 /* If it didn't work, then kill the object */
1807 ObMakeTemporaryObject(DriverObject
);
1808 ObDereferenceObject(DriverObject
);
1811 /* Return the Status */
1821 IN PDRIVER_OBJECT DriverObject
1824 /* Simply derefence the Object */
1825 ObDereferenceObject(DriverObject
);
1832 * Loads a device driver.
1836 * Name of the service to load (registry key).
1846 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1848 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1849 UNICODE_STRING ImagePath
;
1850 UNICODE_STRING ServiceName
;
1851 UNICODE_STRING CapturedDriverServiceName
;
1852 KPROCESSOR_MODE PreviousMode
;
1855 PDEVICE_NODE DeviceNode
;
1856 PMODULE_OBJECT ModuleObject
;
1857 PDRIVER_OBJECT DriverObject
;
1862 PreviousMode
= KeGetPreviousMode();
1865 * Check security privileges
1868 /* FIXME: Uncomment when privileges will be correctly implemented. */
1870 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1872 DPRINT("Privilege not held\n");
1873 return STATUS_PRIVILEGE_NOT_HELD
;
1877 Status
= RtlCaptureUnicodeString(&CapturedDriverServiceName
,
1882 if (!NT_SUCCESS(Status
))
1887 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1889 RtlInitUnicodeString(&ImagePath
, NULL
);
1892 * Get the service name from the registry key name.
1894 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1896 ServiceName
= CapturedDriverServiceName
;
1897 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1898 while (CapturedDriverServiceName
.Buffer
!= cur
)
1902 ServiceName
.Buffer
= cur
+ 1;
1903 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1904 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1905 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1915 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1917 RtlInitUnicodeString(&ImagePath
, NULL
);
1919 QueryTable
[0].Name
= L
"Type";
1920 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1921 QueryTable
[0].EntryContext
= &Type
;
1923 QueryTable
[1].Name
= L
"ImagePath";
1924 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1925 QueryTable
[1].EntryContext
= &ImagePath
;
1927 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1928 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1930 if (!NT_SUCCESS(Status
))
1932 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1933 ExFreePool(ImagePath
.Buffer
);
1934 goto ReleaseCapturedString
;
1938 * Normalize the image path for all later processing.
1941 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1943 if (!NT_SUCCESS(Status
))
1945 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1946 goto ReleaseCapturedString
;
1949 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1950 DPRINT("Type: %lx\n", Type
);
1953 * See, if the driver module isn't already loaded
1956 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1957 if (ModuleObject
!= NULL
)
1959 DPRINT("Image already loaded\n");
1960 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1961 goto ReleaseCapturedString
;
1965 * Create device node
1968 /* Use IopRootDeviceNode for now */
1969 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1971 if (!NT_SUCCESS(Status
))
1973 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1974 goto ReleaseCapturedString
;
1978 * Load the driver module
1981 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1983 if (!NT_SUCCESS(Status
))
1985 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1986 IopFreeDeviceNode(DeviceNode
);
1987 goto ReleaseCapturedString
;
1991 * Set a service name for the device node
1994 RtlpCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
, NonPagedPool
);
1997 * Initialize the driver module
2000 Status
= IopInitializeDriverModule(
2003 &DeviceNode
->ServiceName
,
2004 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2005 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2008 if (!NT_SUCCESS(Status
))
2010 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
2011 LdrUnloadModule(ModuleObject
);
2012 IopFreeDeviceNode(DeviceNode
);
2013 goto ReleaseCapturedString
;
2016 IopInitializeDevice(DeviceNode
, DriverObject
);
2017 Status
= IopStartDevice(DeviceNode
);
2019 ReleaseCapturedString
:
2020 RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2030 * Unloads a legacy device driver.
2034 * Name of the service to unload (registry key).
2044 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2046 return IopUnloadDriver(DriverServiceName
, FALSE
);
2050 * IoRegisterDriverReinitialization
2057 IoRegisterDriverReinitialization(
2058 PDRIVER_OBJECT DriverObject
,
2059 PDRIVER_REINITIALIZE ReinitRoutine
,
2062 PDRIVER_REINIT_ITEM ReinitItem
;
2064 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2065 if (ReinitItem
== NULL
)
2068 ReinitItem
->DriverObject
= DriverObject
;
2069 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2070 ReinitItem
->Context
= Context
;
2072 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2074 ExInterlockedInsertTailList(
2075 &DriverReinitListHead
,
2076 &ReinitItem
->ItemEntry
,
2077 &DriverReinitListLock
);
2085 IoRegisterBootDriverReinitialization(
2086 IN PDRIVER_OBJECT DriverObject
,
2087 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2091 PDRIVER_REINIT_ITEM ReinitItem
;
2093 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2094 if (ReinitItem
== NULL
)
2097 ReinitItem
->DriverObject
= DriverObject
;
2098 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2099 ReinitItem
->Context
= Context
;
2101 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2103 ExInterlockedInsertTailList(
2104 &DriverBootReinitListHead
,
2105 &ReinitItem
->ItemEntry
,
2106 &DriverReinitListLock
);
2110 * IoAllocateDriverObjectExtension
2117 IoAllocateDriverObjectExtension(
2118 PDRIVER_OBJECT DriverObject
,
2119 PVOID ClientIdentificationAddress
,
2120 ULONG DriverObjectExtensionSize
,
2121 PVOID
*DriverObjectExtension
)
2124 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2125 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2127 NewDriverExtension
= ExAllocatePoolWithTag(
2129 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2130 DriverObjectExtensionSize
,
2131 TAG_DRIVER_EXTENSION
);
2133 if (NewDriverExtension
== NULL
)
2135 return STATUS_INSUFFICIENT_RESOURCES
;
2138 OldIrql
= KeRaiseIrqlToDpcLevel();
2140 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2141 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2143 for (DriverExtensions
= DriverObject
->DriverSection
;
2144 DriverExtensions
!= NULL
;
2145 DriverExtensions
= DriverExtensions
->Link
)
2147 if (DriverExtensions
->ClientIdentificationAddress
==
2148 ClientIdentificationAddress
)
2150 KfLowerIrql(OldIrql
);
2151 return STATUS_OBJECT_NAME_COLLISION
;
2155 DriverObject
->DriverSection
= NewDriverExtension
;
2157 KfLowerIrql(OldIrql
);
2159 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2161 return STATUS_SUCCESS
;
2165 * IoGetDriverObjectExtension
2172 IoGetDriverObjectExtension(
2173 PDRIVER_OBJECT DriverObject
,
2174 PVOID ClientIdentificationAddress
)
2177 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2179 OldIrql
= KeRaiseIrqlToDpcLevel();
2181 for (DriverExtensions
= DriverObject
->DriverSection
;
2182 DriverExtensions
!= NULL
&&
2183 DriverExtensions
->ClientIdentificationAddress
!=
2184 ClientIdentificationAddress
;
2185 DriverExtensions
= DriverExtensions
->Link
)
2188 KfLowerIrql(OldIrql
);
2190 if (DriverExtensions
== NULL
)
2193 return &DriverExtensions
->Extension
;