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 RTL_CONSTANT_STRING(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 0x%p)\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 CHAR TextBuffer
[256];
341 if (SetupMode
) return;
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, 0x%p)\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, 0x%p, %x, 0x%p, 0x%p)\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
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
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 InitializeObjectAttributes(&ObjectAttributes
,
1055 OBJ_CASE_INSENSITIVE
,
1059 Status
= ZwOpenKey(&KeyHandle
,
1060 KEY_ENUMERATE_SUB_KEYS
,
1062 if (!NT_SUCCESS(Status
))
1067 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1068 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1069 if (KeyInfo
== NULL
)
1072 return(STATUS_INSUFFICIENT_RESOURCES
);
1078 Status
= ZwEnumerateKey(KeyHandle
,
1080 KeyBasicInformation
,
1084 if (NT_SUCCESS(Status
))
1086 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1089 SubKeyName
.Length
= KeyInfo
->NameLength
;
1090 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1091 SubKeyName
.Buffer
= KeyInfo
->Name
;
1092 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1094 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1095 IopCreateServiceListEntry(&SubKeyName
);
1099 if (!NT_SUCCESS(Status
))
1105 ExFreePool(KeyInfo
);
1108 DPRINT("IoCreateDriverList() done\n");
1110 return(STATUS_SUCCESS
);
1113 NTSTATUS INIT_FUNCTION
1114 IoDestroyDriverList(VOID
)
1116 PLIST_ENTRY GroupEntry
;
1117 PLIST_ENTRY ServiceEntry
;
1118 PSERVICE_GROUP CurrentGroup
;
1119 PSERVICE CurrentService
;
1121 DPRINT("IoDestroyDriverList() called\n");
1123 /* Destroy group list */
1124 GroupEntry
= GroupListHead
.Flink
;
1125 while (GroupEntry
!= &GroupListHead
)
1127 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1129 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1130 RemoveEntryList(GroupEntry
);
1131 if (CurrentGroup
->TagArray
)
1133 ExFreePool(CurrentGroup
->TagArray
);
1135 ExFreePool(CurrentGroup
);
1137 GroupEntry
= GroupListHead
.Flink
;
1140 /* Destroy service list */
1141 ServiceEntry
= ServiceListHead
.Flink
;
1142 while (ServiceEntry
!= &ServiceListHead
)
1144 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1146 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1147 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1148 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1149 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1150 RemoveEntryList(ServiceEntry
);
1151 ExFreePool(CurrentService
);
1153 ServiceEntry
= ServiceListHead
.Flink
;
1156 DPRINT("IoDestroyDriverList() done\n");
1158 return(STATUS_SUCCESS
);
1161 VOID STATIC INIT_FUNCTION
1162 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1166 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1168 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1173 * IopInitializeBuiltinDriver
1175 * Initialize a driver that is already loaded in memory.
1178 NTSTATUS FASTCALL INIT_FUNCTION
1179 IopInitializeBuiltinDriver(
1180 PDEVICE_NODE ModuleDeviceNode
,
1181 PVOID ModuleLoadBase
,
1185 PMODULE_OBJECT ModuleObject
;
1186 PDEVICE_NODE DeviceNode
;
1187 PDRIVER_OBJECT DriverObject
;
1189 PCHAR FileNameWithoutPath
;
1190 LPWSTR FileExtension
;
1192 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1193 FileName
, ModuleLoadBase
, ModuleLength
);
1196 * Display 'Loading XXX...' message
1198 IopDisplayLoadingMessage(FileName
, FALSE
);
1201 * Determine the right device object
1204 if (ModuleDeviceNode
== NULL
)
1206 /* Use IopRootDeviceNode for now */
1207 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1208 if (!NT_SUCCESS(Status
))
1210 CPRINT("Driver load failed, status (%x)\n", Status
);
1215 DeviceNode
= ModuleDeviceNode
;
1219 * Generate filename without path (not needed by freeldr)
1222 FileNameWithoutPath
= strrchr(FileName
, '\\');
1223 if (FileNameWithoutPath
== NULL
)
1225 FileNameWithoutPath
= FileName
;
1232 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1233 FileNameWithoutPath
);
1234 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1236 if (!NT_SUCCESS(Status
))
1238 if (ModuleDeviceNode
== NULL
)
1239 IopFreeDeviceNode(DeviceNode
);
1240 CPRINT("Driver load failed, status (%x)\n", Status
);
1245 KDB_SYMBOLFILE_HOOK(FileName
);
1248 * Strip the file extension from ServiceName
1251 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1252 if (FileExtension
!= NULL
)
1254 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1255 FileExtension
[0] = 0;
1259 * Initialize the driver
1262 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1263 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1265 if (!NT_SUCCESS(Status
))
1267 if (ModuleDeviceNode
== NULL
)
1268 IopFreeDeviceNode(DeviceNode
);
1269 CPRINT("Driver load failed, status (%x)\n", Status
);
1273 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1274 if (NT_SUCCESS(Status
))
1276 Status
= IopStartDevice(DeviceNode
);
1283 * IopInitializeBootDrivers
1285 * Initialize boot drivers and free memory for boot files.
1295 IopInitializeBootDrivers(VOID
)
1297 ULONG BootDriverCount
;
1303 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1305 UNICODE_STRING DriverName
;
1308 DPRINT("IopInitializeBootDrivers()\n");
1310 BootDriverCount
= 0;
1311 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1313 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1314 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1315 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1316 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1317 Extension
= strrchr(ModuleName
, '.');
1318 if (Extension
== NULL
)
1321 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1323 /* Process symbols for *.exe and *.dll */
1324 KDB_SYMBOLFILE_HOOK(ModuleName
);
1326 /* Log *.exe and *.dll files */
1327 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1328 IopBootLog(&DriverName
, TRUE
);
1329 RtlFreeUnicodeString(&DriverName
);
1331 else if (!_stricmp(Extension
, ".sys"))
1333 /* Initialize and log boot start driver */
1336 Status
= IopInitializeBuiltinDriver(NULL
,
1340 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1341 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1342 RtlFreeUnicodeString(&DriverName
);
1349 * Free memory for all boot files, except ntoskrnl.exe.
1351 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1353 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1354 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1357 KeLoaderBlock
.ModsCount
= 0;
1359 if (BootDriverCount
== 0)
1361 DbgPrint("No boot drivers available.\n");
1366 static INIT_FUNCTION NTSTATUS
1367 IopLoadDriver(PSERVICE Service
)
1369 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1371 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1372 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1373 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1374 if (!NT_SUCCESS(Status
))
1376 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1378 if (Service
->ErrorControl
== 1)
1382 else if (Service
->ErrorControl
== 2)
1384 if (IsLastKnownGood
== FALSE
)
1386 /* Boot last known good configuration */
1389 else if (Service
->ErrorControl
== 3)
1391 if (IsLastKnownGood
== FALSE
)
1393 /* Boot last known good configuration */
1407 * IopInitializeSystemDrivers
1409 * Load drivers marked as system start.
1419 IopInitializeSystemDrivers(VOID
)
1421 PLIST_ENTRY GroupEntry
;
1422 PLIST_ENTRY ServiceEntry
;
1423 PSERVICE_GROUP CurrentGroup
;
1424 PSERVICE CurrentService
;
1428 DPRINT("IopInitializeSystemDrivers()\n");
1430 GroupEntry
= GroupListHead
.Flink
;
1431 while (GroupEntry
!= &GroupListHead
)
1433 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1435 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1437 /* Load all drivers with a valid tag */
1438 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1440 ServiceEntry
= ServiceListHead
.Flink
;
1441 while (ServiceEntry
!= &ServiceListHead
)
1443 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1445 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1446 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1447 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1448 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1450 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1451 Status
= IopLoadDriver(CurrentService
);
1453 ServiceEntry
= ServiceEntry
->Flink
;
1457 /* Load all drivers without a tag or with an invalid tag */
1458 ServiceEntry
= ServiceListHead
.Flink
;
1459 while (ServiceEntry
!= &ServiceListHead
)
1461 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1462 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1463 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1464 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1466 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1468 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1473 if (i
>= CurrentGroup
->TagCount
)
1475 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1476 Status
= IopLoadDriver(CurrentService
);
1479 ServiceEntry
= ServiceEntry
->Flink
;
1482 GroupEntry
= GroupEntry
->Flink
;
1485 DPRINT("IopInitializeSystemDrivers() done\n");
1491 * Unloads a device driver.
1495 * Name of the service to unload (registry key).
1498 * Whether to unload Plug & Plug or only legacy drivers. If this
1499 * parameter is set to FALSE, the routine will unload only legacy
1506 * Guard the whole function by SEH.
1510 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1512 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1513 UNICODE_STRING ImagePath
;
1514 UNICODE_STRING ServiceName
;
1515 UNICODE_STRING ObjectName
;
1516 PDRIVER_OBJECT DriverObject
;
1517 PMODULE_OBJECT ModuleObject
;
1521 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1524 * Get the service name from the registry key name
1527 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1529 Start
= DriverServiceName
->Buffer
;
1533 RtlInitUnicodeString(&ServiceName
, Start
);
1536 * Construct the driver object name
1539 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1540 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1541 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1542 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1543 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1544 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1547 * Find the driver object
1550 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1551 KernelMode
, 0, (PVOID
*)&DriverObject
);
1553 if (!NT_SUCCESS(Status
))
1555 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1560 * Free the buffer for driver object name
1563 ExFreePool(ObjectName
.Buffer
);
1566 * Get path of service...
1569 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1571 RtlInitUnicodeString(&ImagePath
, NULL
);
1573 QueryTable
[0].Name
= L
"ImagePath";
1574 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1575 QueryTable
[0].EntryContext
= &ImagePath
;
1577 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1578 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1580 if (!NT_SUCCESS(Status
))
1582 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1587 * Normalize the image path for all later processing.
1590 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1592 if (!NT_SUCCESS(Status
))
1594 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1599 * ... and check if it's loaded
1602 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1603 if (ModuleObject
== NULL
)
1605 return STATUS_UNSUCCESSFUL
;
1609 * Free the service path
1612 ExFreePool(ImagePath
.Buffer
);
1615 * Unload the module and release the references to the device object
1618 if (DriverObject
->DriverUnload
)
1619 (*DriverObject
->DriverUnload
)(DriverObject
);
1620 ObDereferenceObject(DriverObject
);
1621 ObDereferenceObject(DriverObject
);
1622 LdrUnloadModule(ModuleObject
);
1624 return STATUS_SUCCESS
;
1628 IopMarkLastReinitializeDriver(VOID
)
1632 KeAcquireSpinLock(&DriverReinitListLock
,
1635 if (IsListEmpty(&DriverReinitListHead
))
1637 DriverReinitTailEntry
= NULL
;
1641 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1644 KeReleaseSpinLock(&DriverReinitListLock
,
1650 IopReinitializeDrivers(VOID
)
1652 PDRIVER_REINIT_ITEM ReinitItem
;
1656 KeAcquireSpinLock(&DriverReinitListLock
,
1659 Entry
= DriverReinitTailEntry
;
1661 KeReleaseSpinLock(&DriverReinitListLock
,
1671 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1672 &DriverReinitListLock
);
1676 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1678 /* Increment reinitialization counter */
1679 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1681 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1682 ReinitItem
->Context
,
1683 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1687 if (Entry
== DriverReinitTailEntry
)
1692 /* PUBLIC FUNCTIONS ***********************************************************/
1701 IN PUNICODE_STRING DriverName
, OPTIONAL
1702 IN PDRIVER_INITIALIZE InitializationFunction
1705 WCHAR NameBuffer
[100];
1707 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1709 OBJECT_ATTRIBUTES ObjectAttributes
;
1711 PDRIVER_OBJECT DriverObject
;
1712 UNICODE_STRING ServiceKeyName
;
1716 /* First, create a unique name for the driver if we don't have one */
1719 /* Create a random name and set up the string*/
1720 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1721 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1722 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1723 LocalDriverName
.Buffer
= NameBuffer
;
1727 /* So we can avoid another code path, use a local var */
1728 LocalDriverName
= *DriverName
;
1731 /* Initialize the Attributes */
1732 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1733 InitializeObjectAttributes(&ObjectAttributes
,
1735 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1739 /* Create the Object */
1740 Status
= ObCreateObject(KernelMode
,
1748 (PVOID
*)&DriverObject
);
1750 /* Return on failure */
1751 if (!NT_SUCCESS(Status
)) return Status
;
1753 /* Set up the Object */
1754 RtlZeroMemory(DriverObject
, ObjectSize
);
1755 DriverObject
->Type
= IO_TYPE_DRIVER
;
1756 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1757 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1758 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1759 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1760 DriverObject
->DriverInit
= InitializationFunction
;
1762 /* Invalidate all Major Functions */
1763 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1765 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1768 /* Set up the Service Key Name */
1769 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1770 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1771 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1772 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1773 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1774 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1776 /* Also store it in the Driver Object. This is a bit of a hack. */
1777 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1779 /* Add the Object and get its handle */
1780 Status
= ObInsertObject(DriverObject
,
1787 /* Return on Failure */
1788 if (!NT_SUCCESS(Status
)) return Status
;
1790 /* Now reference it */
1791 Status
= ObReferenceObjectByHandle(hDriver
,
1795 (PVOID
*)&DriverObject
,
1799 /* Finally, call its init function */
1800 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1802 if (!NT_SUCCESS(Status
)) {
1803 /* If it didn't work, then kill the object */
1804 ObMakeTemporaryObject(DriverObject
);
1805 ObDereferenceObject(DriverObject
);
1808 /* Return the Status */
1818 IN PDRIVER_OBJECT DriverObject
1821 /* Simply derefence the Object */
1822 ObDereferenceObject(DriverObject
);
1829 * Loads a device driver.
1833 * Name of the service to load (registry key).
1843 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1845 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1846 UNICODE_STRING ImagePath
;
1847 UNICODE_STRING ServiceName
;
1848 UNICODE_STRING CapturedDriverServiceName
;
1849 KPROCESSOR_MODE PreviousMode
;
1852 PDEVICE_NODE DeviceNode
;
1853 PMODULE_OBJECT ModuleObject
;
1854 PDRIVER_OBJECT DriverObject
;
1859 PreviousMode
= KeGetPreviousMode();
1862 * Check security privileges
1865 /* FIXME: Uncomment when privileges will be correctly implemented. */
1867 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1869 DPRINT("Privilege not held\n");
1870 return STATUS_PRIVILEGE_NOT_HELD
;
1874 Status
= RtlCaptureUnicodeString(&CapturedDriverServiceName
,
1879 if (!NT_SUCCESS(Status
))
1884 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1886 RtlInitUnicodeString(&ImagePath
, NULL
);
1889 * Get the service name from the registry key name.
1891 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1893 ServiceName
= CapturedDriverServiceName
;
1894 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1895 while (CapturedDriverServiceName
.Buffer
!= cur
)
1899 ServiceName
.Buffer
= cur
+ 1;
1900 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1901 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1902 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1912 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1914 RtlInitUnicodeString(&ImagePath
, NULL
);
1916 QueryTable
[0].Name
= L
"Type";
1917 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1918 QueryTable
[0].EntryContext
= &Type
;
1920 QueryTable
[1].Name
= L
"ImagePath";
1921 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1922 QueryTable
[1].EntryContext
= &ImagePath
;
1924 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1925 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1927 if (!NT_SUCCESS(Status
))
1929 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1930 ExFreePool(ImagePath
.Buffer
);
1931 goto ReleaseCapturedString
;
1935 * Normalize the image path for all later processing.
1938 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1940 if (!NT_SUCCESS(Status
))
1942 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1943 goto ReleaseCapturedString
;
1946 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1947 DPRINT("Type: %lx\n", Type
);
1950 * See, if the driver module isn't already loaded
1953 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1954 if (ModuleObject
!= NULL
)
1956 DPRINT("Image already loaded\n");
1957 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1958 goto ReleaseCapturedString
;
1962 * Create device node
1965 /* Use IopRootDeviceNode for now */
1966 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1968 if (!NT_SUCCESS(Status
))
1970 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1971 goto ReleaseCapturedString
;
1975 * Load the driver module
1978 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1980 if (!NT_SUCCESS(Status
))
1982 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1983 IopFreeDeviceNode(DeviceNode
);
1984 goto ReleaseCapturedString
;
1988 * Set a service name for the device node
1991 RtlpCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
, NonPagedPool
);
1994 * Initialize the driver module
1997 Status
= IopInitializeDriverModule(
2000 &DeviceNode
->ServiceName
,
2001 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2002 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2005 if (!NT_SUCCESS(Status
))
2007 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
2008 LdrUnloadModule(ModuleObject
);
2009 IopFreeDeviceNode(DeviceNode
);
2010 goto ReleaseCapturedString
;
2013 IopInitializeDevice(DeviceNode
, DriverObject
);
2014 Status
= IopStartDevice(DeviceNode
);
2016 ReleaseCapturedString
:
2017 RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2027 * Unloads a legacy device driver.
2031 * Name of the service to unload (registry key).
2041 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2043 return IopUnloadDriver(DriverServiceName
, FALSE
);
2047 * IoRegisterDriverReinitialization
2054 IoRegisterDriverReinitialization(
2055 PDRIVER_OBJECT DriverObject
,
2056 PDRIVER_REINITIALIZE ReinitRoutine
,
2059 PDRIVER_REINIT_ITEM ReinitItem
;
2061 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2062 if (ReinitItem
== NULL
)
2065 ReinitItem
->DriverObject
= DriverObject
;
2066 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2067 ReinitItem
->Context
= Context
;
2069 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2071 ExInterlockedInsertTailList(
2072 &DriverReinitListHead
,
2073 &ReinitItem
->ItemEntry
,
2074 &DriverReinitListLock
);
2082 IoRegisterBootDriverReinitialization(
2083 IN PDRIVER_OBJECT DriverObject
,
2084 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2088 PDRIVER_REINIT_ITEM ReinitItem
;
2090 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2091 if (ReinitItem
== NULL
)
2094 ReinitItem
->DriverObject
= DriverObject
;
2095 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2096 ReinitItem
->Context
= Context
;
2098 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2100 ExInterlockedInsertTailList(
2101 &DriverBootReinitListHead
,
2102 &ReinitItem
->ItemEntry
,
2103 &DriverReinitListLock
);
2107 * IoAllocateDriverObjectExtension
2114 IoAllocateDriverObjectExtension(
2115 PDRIVER_OBJECT DriverObject
,
2116 PVOID ClientIdentificationAddress
,
2117 ULONG DriverObjectExtensionSize
,
2118 PVOID
*DriverObjectExtension
)
2121 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2122 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2124 NewDriverExtension
= ExAllocatePoolWithTag(
2126 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2127 DriverObjectExtensionSize
,
2128 TAG_DRIVER_EXTENSION
);
2130 if (NewDriverExtension
== NULL
)
2132 return STATUS_INSUFFICIENT_RESOURCES
;
2135 OldIrql
= KeRaiseIrqlToDpcLevel();
2137 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2138 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2140 for (DriverExtensions
= DriverObject
->DriverSection
;
2141 DriverExtensions
!= NULL
;
2142 DriverExtensions
= DriverExtensions
->Link
)
2144 if (DriverExtensions
->ClientIdentificationAddress
==
2145 ClientIdentificationAddress
)
2147 KfLowerIrql(OldIrql
);
2148 return STATUS_OBJECT_NAME_COLLISION
;
2152 DriverObject
->DriverSection
= NewDriverExtension
;
2154 KfLowerIrql(OldIrql
);
2156 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2158 return STATUS_SUCCESS
;
2162 * IoGetDriverObjectExtension
2169 IoGetDriverObjectExtension(
2170 PDRIVER_OBJECT DriverObject
,
2171 PVOID ClientIdentificationAddress
)
2174 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2176 OldIrql
= KeRaiseIrqlToDpcLevel();
2178 for (DriverExtensions
= DriverObject
->DriverSection
;
2179 DriverExtensions
!= NULL
&&
2180 DriverExtensions
->ClientIdentificationAddress
!=
2181 ClientIdentificationAddress
;
2182 DriverExtensions
= DriverExtensions
->Link
)
2185 KfLowerIrql(OldIrql
);
2187 if (DriverExtensions
== NULL
)
2190 return &DriverExtensions
->Extension
;