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
;
23 LdrProcessModule(PVOID ModuleLoadBase
,
24 PUNICODE_STRING ModuleName
,
25 PMODULE_OBJECT
*ModuleObject
);
27 typedef struct _SERVICE_GROUP
29 LIST_ENTRY GroupListEntry
;
30 UNICODE_STRING GroupName
;
31 BOOLEAN ServicesRunning
;
34 } SERVICE_GROUP
, *PSERVICE_GROUP
;
36 typedef struct _SERVICE
38 LIST_ENTRY ServiceListEntry
;
39 UNICODE_STRING ServiceName
;
40 UNICODE_STRING RegistryPath
;
41 UNICODE_STRING ServiceGroup
;
42 UNICODE_STRING ImagePath
;
49 /* BOOLEAN ServiceRunning;*/ // needed ??
52 typedef struct _DRIVER_REINIT_ITEM
55 PDRIVER_OBJECT DriverObject
;
56 PDRIVER_REINITIALIZE ReinitRoutine
;
58 } DRIVER_REINIT_ITEM
, *PDRIVER_REINIT_ITEM
;
60 /* GLOBALS ********************************************************************/
62 static LIST_ENTRY DriverReinitListHead
;
63 static KSPIN_LOCK DriverReinitListLock
;
64 static PLIST_ENTRY DriverReinitTailEntry
;
66 static PLIST_ENTRY DriverBootReinitTailEntry
;
67 static LIST_ENTRY DriverBootReinitListHead
;
68 static KSPIN_LOCK DriverBootReinitListLock
;
70 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
71 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
73 static UNICODE_STRING IopHardwareDatabaseKey
=
74 ROS_STRING_INITIALIZER(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
76 POBJECT_TYPE EXPORTED IoDriverObjectType
= NULL
;
78 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
79 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
81 /* DECLARATIONS ***************************************************************/
88 POBJECT_ATTRIBUTES ObjectAttributes
);
91 IopDeleteDriver(PVOID ObjectBody
);
93 /* PRIVATE FUNCTIONS **********************************************************/
96 IopInitDriverImplementation(VOID
)
98 /* Register the process object type */
99 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
100 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'R');
101 IoDriverObjectType
->TotalObjects
= 0;
102 IoDriverObjectType
->TotalHandles
= 0;
103 IoDriverObjectType
->PeakObjects
= 0;
104 IoDriverObjectType
->PeakHandles
= 0;
105 IoDriverObjectType
->PagedPoolCharge
= 0;
106 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(DRIVER_OBJECT
);
107 IoDriverObjectType
->Dump
= NULL
;
108 IoDriverObjectType
->Open
= NULL
;
109 IoDriverObjectType
->Close
= NULL
;
110 IoDriverObjectType
->Delete
= IopDeleteDriver
;
111 IoDriverObjectType
->Parse
= NULL
;
112 IoDriverObjectType
->Security
= NULL
;
113 IoDriverObjectType
->QueryName
= NULL
;
114 IoDriverObjectType
->OkayToClose
= NULL
;
115 IoDriverObjectType
->Create
= IopCreateDriver
;
116 IoDriverObjectType
->DuplicationNotify
= NULL
;
117 RtlInitUnicodeString(&IoDriverObjectType
->TypeName
, L
"Driver");
119 ObpCreateTypeObject(IoDriverObjectType
);
121 InitializeListHead(&DriverReinitListHead
);
122 KeInitializeSpinLock(&DriverReinitListLock
);
123 DriverReinitTailEntry
= NULL
;
125 InitializeListHead(&DriverBootReinitListHead
);
126 KeInitializeSpinLock(&DriverBootReinitListLock
);
127 DriverBootReinitTailEntry
= NULL
;
131 IopInvalidDeviceRequest(
132 PDEVICE_OBJECT DeviceObject
,
135 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
136 Irp
->IoStatus
.Information
= 0;
137 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
138 return STATUS_INVALID_DEVICE_REQUEST
;
146 POBJECT_ATTRIBUTES ObjectAttributes
)
148 PDRIVER_OBJECT Object
= ObjectBody
;
151 DPRINT("IopCreateDriver(ObjectBody %x, Parent %x, RemainingPath %S)\n",
152 ObjectBody
, Parent
, RemainingPath
);
154 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
155 return STATUS_UNSUCCESSFUL
;
157 /* Create driver extension */
158 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
159 ExAllocatePoolWithTag(
161 sizeof(DRIVER_EXTENSION
),
162 TAG_DRIVER_EXTENSION
);
164 if (Object
->DriverExtension
== NULL
)
166 return STATUS_NO_MEMORY
;
169 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
171 Object
->Type
= IO_TYPE_DRIVER
;
173 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
174 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
176 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
178 return STATUS_SUCCESS
;
182 IopDeleteDriver(PVOID ObjectBody
)
184 PDRIVER_OBJECT Object
= ObjectBody
;
186 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
188 DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody
);
190 ExFreePool(Object
->DriverExtension
);
191 ExFreePool(Object
->DriverName
.Buffer
);
193 OldIrql
= KeRaiseIrqlToDpcLevel();
195 for (DriverExtension
= Object
->DriverSection
;
196 DriverExtension
!= NULL
;
197 DriverExtension
= NextDriverExtension
)
199 NextDriverExtension
= DriverExtension
->Link
;
200 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
203 KfLowerIrql(OldIrql
);
207 IopCreateDriverObject(
208 PDRIVER_OBJECT
*DriverObject
,
209 PUNICODE_STRING ServiceName
,
210 ULONG CreateAttributes
,
212 PVOID DriverImageStart
,
213 ULONG DriverImageSize
)
215 PDRIVER_OBJECT Object
;
216 WCHAR NameBuffer
[MAX_PATH
];
217 UNICODE_STRING DriverName
;
218 OBJECT_ATTRIBUTES ObjectAttributes
;
222 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
223 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
225 *DriverObject
= NULL
;
227 /* Create ModuleName string */
228 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
230 if (FileSystem
== TRUE
)
231 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
233 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
234 wcscat(NameBuffer
, ServiceName
->Buffer
);
236 RtlInitUnicodeString(&DriverName
, NameBuffer
);
237 DPRINT("Driver name: '%wZ'\n", &DriverName
);
239 Buffer
= (PWSTR
)ExAllocatePool(NonPagedPool
, DriverName
.Length
);
240 /* If we don't success, it is not a problem. Our driver
241 * object will not have associated driver name... */
245 RtlInitUnicodeString(&DriverName
, NULL
);
248 /* Initialize ObjectAttributes for driver object */
249 InitializeObjectAttributes(
252 CreateAttributes
| OBJ_PERMANENT
,
256 /* Create driver object */
257 Status
= ObCreateObject(
263 sizeof(DRIVER_OBJECT
),
268 if (!NT_SUCCESS(Status
))
273 Object
->DriverStart
= DriverImageStart
;
274 Object
->DriverSize
= DriverImageSize
;
277 if (!Object
->DriverName
.Buffer
)
279 Object
->DriverName
.Buffer
= Buffer
;
280 Object
->DriverName
.Length
= Object
->DriverName
.MaximumLength
= DriverName
.Length
;
281 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
287 *DriverObject
= Object
;
289 return STATUS_SUCCESS
;
293 * IopDisplayLoadingMessage
295 * Display 'Loading XXX...' message.
299 IopDisplayLoadingMessage(PWCHAR ServiceName
)
301 CHAR TextBuffer
[256];
302 sprintf(TextBuffer
, "Loading %S...\n", ServiceName
);
303 HalDisplayString(TextBuffer
);
307 * IopNormalizeImagePath
309 * Normalize an image path to contain complete path.
313 * The input path and on exit the result path. ImagePath.Buffer
314 * must be allocated by ExAllocatePool on input. Caller is responsible
315 * for freeing the buffer when it's no longer needed.
318 * Name of the service that ImagePath belongs to.
324 * The input image path isn't freed on error.
328 IopNormalizeImagePath(
329 IN OUT PUNICODE_STRING ImagePath
,
330 IN PUNICODE_STRING ServiceName
)
332 UNICODE_STRING InputImagePath
;
337 sizeof(UNICODE_STRING
));
339 if (InputImagePath
.Length
== 0)
341 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
342 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
343 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
344 if (ImagePath
->Buffer
== NULL
)
345 return STATUS_NO_MEMORY
;
347 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
348 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
349 wcscat(ImagePath
->Buffer
, L
".sys");
351 if (InputImagePath
.Buffer
[0] != L
'\\')
353 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
354 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
355 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
356 if (ImagePath
->Buffer
== NULL
)
357 return STATUS_NO_MEMORY
;
359 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
360 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
361 ExFreePool(InputImagePath
.Buffer
);
364 return STATUS_SUCCESS
;
368 * IopLoadServiceModule
370 * Load a module specified by registry settings for service.
374 * Name of the service to load.
381 IopLoadServiceModule(
382 IN PUNICODE_STRING ServiceName
,
383 OUT PMODULE_OBJECT
*ModuleObject
)
385 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
387 UNICODE_STRING ServiceImagePath
;
390 DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName
, ModuleObject
);
393 * Get information about the service.
396 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
398 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
400 QueryTable
[0].Name
= L
"Start";
401 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
402 QueryTable
[0].EntryContext
= &ServiceStart
;
404 QueryTable
[1].Name
= L
"ImagePath";
405 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
406 QueryTable
[1].EntryContext
= &ServiceImagePath
;
408 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
409 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
411 if (!NT_SUCCESS(Status
))
413 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
417 IopDisplayLoadingMessage(ServiceName
->Buffer
);
420 * Normalize the image path for all later processing.
423 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
425 if (!NT_SUCCESS(Status
))
427 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
435 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
437 if (*ModuleObject
== NULL
)
439 Status
= STATUS_UNSUCCESSFUL
;
442 * Special case for boot modules that were loaded by boot loader.
445 if (ServiceStart
== 0)
448 CHAR SearchName
[256];
450 PLOADER_MODULE KeLoaderModules
=
451 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
455 * Improve this searching algorithm by using the image name
456 * stored in registry entry ImageName and use the whole path
457 * (requires change in FreeLoader).
460 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
461 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
463 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
464 if (!_stricmp(ModuleName
, SearchName
))
466 DPRINT("Initializing boot module\n");
468 /* Tell, that the module is already loaded */
469 KeLoaderModules
[i
].Reserved
= 1;
471 Status
= LdrProcessModule(
472 (PVOID
)KeLoaderModules
[i
].ModStart
,
476 KDB_SYMBOLFILE_HOOK(SearchName
);
484 * Case for rest of the drivers (except disabled)
487 else if (ServiceStart
< 4)
489 DPRINT("Loading module\n");
490 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
495 DPRINT("Module already loaded\n");
496 Status
= STATUS_IMAGE_ALREADY_LOADED
;
499 ExFreePool(ServiceImagePath
.Buffer
);
502 * Now check if the module was loaded successfully.
505 if (!NT_SUCCESS(Status
))
507 DPRINT("Module loading failed (Status %x)\n", Status
);
510 DPRINT("Module loading (Status %x)\n", Status
);
516 * IopInitializeDriverModule
518 * Initalize a loaded driver.
522 * Pointer to device node.
525 * Module object representing the driver. It can be retrieve by
526 * IopLoadServiceModule.
529 * Name of the service (as in registry).
532 * Set to TRUE for file system drivers.
535 * On successful return this contains the driver object representing
540 IopInitializeDriverModule(
541 IN PDEVICE_NODE DeviceNode
,
542 IN PMODULE_OBJECT ModuleObject
,
543 IN PUNICODE_STRING ServiceName
,
544 IN BOOLEAN FileSystemDriver
,
545 OUT PDRIVER_OBJECT
*DriverObject
)
547 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
548 UNICODE_STRING RegistryKey
;
549 PDRIVER_INITIALIZE DriverEntry
;
552 DriverEntry
= ModuleObject
->EntryPoint
;
554 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
556 RegistryKey
.Length
= 0;
557 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
558 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
559 if (RegistryKey
.Buffer
== NULL
)
561 return STATUS_INSUFFICIENT_RESOURCES
;
563 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
564 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
568 RtlInitUnicodeString(&RegistryKey
, NULL
);
571 Status
= IopCreateDriverObject(
577 ModuleObject
->Length
);
579 if (!NT_SUCCESS(Status
))
581 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
585 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
586 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
588 IopMarkLastReinitializeDriver();
590 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
592 RtlFreeUnicodeString(&RegistryKey
);
594 if (!NT_SUCCESS(Status
))
596 ObMakeTemporaryObject(*DriverObject
);
597 ObDereferenceObject(*DriverObject
);
601 IopReinitializeDrivers();
603 return STATUS_SUCCESS
;
607 * IopAttachFilterDriversCallback
609 * Internal routine used by IopAttachFilterDrivers.
613 IopAttachFilterDriversCallback(
621 PDEVICE_NODE DeviceNode
= Context
;
622 UNICODE_STRING ServiceName
;
624 PMODULE_OBJECT ModuleObject
;
625 PDRIVER_OBJECT DriverObject
;
628 for (Filters
= ValueData
;
629 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
631 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
633 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
634 ServiceName
.Buffer
= Filters
;
635 ServiceName
.MaximumLength
=
636 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
638 /* Load and initialize the filter driver */
639 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
640 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
642 if (!NT_SUCCESS(Status
))
645 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
646 FALSE
, &DriverObject
);
647 if (!NT_SUCCESS(Status
))
652 /* get existing DriverObject pointer */
653 Status
= IopCreateDriverObject(
659 ModuleObject
->Length
);
660 if (!NT_SUCCESS(Status
))
664 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
665 if (!NT_SUCCESS(Status
))
669 return STATUS_SUCCESS
;
673 * IopAttachFilterDrivers
675 * Load filter drivers for specified device node.
679 * Set to TRUE for loading lower level filters or FALSE for upper
684 IopAttachFilterDrivers(
685 PDEVICE_NODE DeviceNode
,
688 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
690 UNICODE_STRING Class
;
691 WCHAR ClassBuffer
[40];
695 * First load the device filters
698 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
700 QueryTable
[0].Name
= L
"LowerFilters";
702 QueryTable
[0].Name
= L
"UpperFilters";
703 QueryTable
[0].EntryContext
= NULL
;
704 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
705 QueryTable
[1].QueryRoutine
= NULL
;
706 QueryTable
[1].Name
= NULL
;
708 KeyBuffer
= ExAllocatePool(
710 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
711 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
712 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
714 RtlQueryRegistryValues(
715 RTL_REGISTRY_ABSOLUTE
,
722 * Now get the class GUID
726 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
727 Class
.Buffer
= ClassBuffer
;
728 QueryTable
[0].QueryRoutine
= NULL
;
729 QueryTable
[0].Name
= L
"ClassGUID";
730 QueryTable
[0].EntryContext
= &Class
;
731 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
733 Status
= RtlQueryRegistryValues(
734 RTL_REGISTRY_ABSOLUTE
,
740 ExFreePool(KeyBuffer
);
743 * Load the class filter driver
746 if (NT_SUCCESS(Status
))
748 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
750 QueryTable
[0].Name
= L
"LowerFilters";
752 QueryTable
[0].Name
= L
"UpperFilters";
753 QueryTable
[0].EntryContext
= NULL
;
754 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
756 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
757 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
758 wcscat(KeyBuffer
, ClassBuffer
);
760 RtlQueryRegistryValues(
761 RTL_REGISTRY_ABSOLUTE
,
767 ExFreePool(KeyBuffer
);
770 return STATUS_SUCCESS
;
773 static NTSTATUS STDCALL
774 IopGetGroupOrderList(PWSTR ValueName
,
781 PSERVICE_GROUP Group
;
783 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
784 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
786 if (ValueType
== REG_BINARY
&&
788 ValueLength
>= sizeof(DWORD
) &&
789 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
791 Group
= (PSERVICE_GROUP
)Context
;
792 Group
->TagCount
= ((PULONG
)ValueData
)[0];
793 if (Group
->TagCount
> 0)
795 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
797 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
798 if (Group
->TagArray
== NULL
)
801 return STATUS_INSUFFICIENT_RESOURCES
;
803 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
808 return STATUS_UNSUCCESSFUL
;
812 return STATUS_SUCCESS
;
815 static NTSTATUS STDCALL
816 IopCreateGroupListEntry(PWSTR ValueName
,
823 PSERVICE_GROUP Group
;
824 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
828 if (ValueType
== REG_SZ
)
830 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
832 Group
= ExAllocatePool(NonPagedPool
,
833 sizeof(SERVICE_GROUP
));
836 return(STATUS_INSUFFICIENT_RESOURCES
);
839 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
841 if (!RtlpCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
, NonPagedPool
))
844 return(STATUS_INSUFFICIENT_RESOURCES
);
847 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
848 QueryTable
[0].Name
= (PWSTR
)ValueData
;
849 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
851 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
856 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
858 InsertTailList(&GroupListHead
,
859 &Group
->GroupListEntry
);
862 return(STATUS_SUCCESS
);
866 static NTSTATUS STDCALL
867 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
869 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
873 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
875 /* Allocate service entry */
876 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
879 DPRINT1("ExAllocatePool() failed\n");
880 return(STATUS_INSUFFICIENT_RESOURCES
);
882 RtlZeroMemory(Service
, sizeof(SERVICE
));
884 /* Get service data */
885 RtlZeroMemory(&QueryTable
,
888 QueryTable
[0].Name
= L
"Start";
889 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
890 QueryTable
[0].EntryContext
= &Service
->Start
;
892 QueryTable
[1].Name
= L
"Type";
893 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
894 QueryTable
[1].EntryContext
= &Service
->Type
;
896 QueryTable
[2].Name
= L
"ErrorControl";
897 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
898 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
900 QueryTable
[3].Name
= L
"Group";
901 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
902 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
904 QueryTable
[4].Name
= L
"ImagePath";
905 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
906 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
908 QueryTable
[5].Name
= L
"Tag";
909 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
910 QueryTable
[5].EntryContext
= &Service
->Tag
;
912 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
917 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
920 * If something goes wrong during RtlQueryRegistryValues
921 * it'll just drop everything on the floor and return,
922 * so you have to check if the buffers were filled.
923 * Luckily we zerofilled the Service.
925 if (Service
->ServiceGroup
.Buffer
)
927 ExFreePool(Service
->ServiceGroup
.Buffer
);
929 if (Service
->ImagePath
.Buffer
)
931 ExFreePool(Service
->ImagePath
.Buffer
);
937 /* Copy service name */
938 Service
->ServiceName
.Length
= ServiceName
->Length
;
939 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
940 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
941 Service
->ServiceName
.MaximumLength
);
942 RtlCopyMemory(Service
->ServiceName
.Buffer
,
944 ServiceName
->Length
);
945 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
947 /* Build registry path */
948 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
949 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
950 MAX_PATH
* sizeof(WCHAR
));
951 wcscpy(Service
->RegistryPath
.Buffer
,
952 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
953 wcscat(Service
->RegistryPath
.Buffer
,
954 Service
->ServiceName
.Buffer
);
955 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
957 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
958 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
959 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
960 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
961 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
962 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
964 /* Append service entry */
965 InsertTailList(&ServiceListHead
,
966 &Service
->ServiceListEntry
);
968 return(STATUS_SUCCESS
);
972 NTSTATUS INIT_FUNCTION
973 IoCreateDriverList(VOID
)
975 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
976 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
977 OBJECT_ATTRIBUTES ObjectAttributes
;
978 UNICODE_STRING ServicesKeyName
;
979 UNICODE_STRING SubKeyName
;
984 ULONG KeyInfoLength
= 0;
985 ULONG ReturnedLength
;
987 DPRINT("IoCreateDriverList() called\n");
989 /* Initialize basic variables */
990 InitializeListHead(&GroupListHead
);
991 InitializeListHead(&ServiceListHead
);
993 /* Build group order list */
994 RtlZeroMemory(&QueryTable
,
997 QueryTable
[0].Name
= L
"List";
998 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1000 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1001 L
"ServiceGroupOrder",
1005 if (!NT_SUCCESS(Status
))
1008 /* Enumerate services and create the service list */
1009 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
1010 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1012 InitializeObjectAttributes(&ObjectAttributes
,
1014 OBJ_CASE_INSENSITIVE
,
1018 Status
= ZwOpenKey(&KeyHandle
,
1019 KEY_ENUMERATE_SUB_KEYS
,
1021 if (!NT_SUCCESS(Status
))
1026 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1027 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1028 if (KeyInfo
== NULL
)
1031 return(STATUS_INSUFFICIENT_RESOURCES
);
1037 Status
= ZwEnumerateKey(KeyHandle
,
1039 KeyBasicInformation
,
1043 if (NT_SUCCESS(Status
))
1045 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1048 SubKeyName
.Length
= KeyInfo
->NameLength
;
1049 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1050 SubKeyName
.Buffer
= KeyInfo
->Name
;
1051 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1053 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1054 IopCreateServiceListEntry(&SubKeyName
);
1058 if (!NT_SUCCESS(Status
))
1064 ExFreePool(KeyInfo
);
1067 DPRINT("IoCreateDriverList() done\n");
1069 return(STATUS_SUCCESS
);
1072 NTSTATUS INIT_FUNCTION
1073 IoDestroyDriverList(VOID
)
1075 PLIST_ENTRY GroupEntry
;
1076 PLIST_ENTRY ServiceEntry
;
1077 PSERVICE_GROUP CurrentGroup
;
1078 PSERVICE CurrentService
;
1080 DPRINT("IoDestroyDriverList() called\n");
1082 /* Destroy group list */
1083 GroupEntry
= GroupListHead
.Flink
;
1084 while (GroupEntry
!= &GroupListHead
)
1086 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1088 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1089 RemoveEntryList(GroupEntry
);
1090 if (CurrentGroup
->TagArray
)
1092 ExFreePool(CurrentGroup
->TagArray
);
1094 ExFreePool(CurrentGroup
);
1096 GroupEntry
= GroupListHead
.Flink
;
1099 /* Destroy service list */
1100 ServiceEntry
= ServiceListHead
.Flink
;
1101 while (ServiceEntry
!= &ServiceListHead
)
1103 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1105 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1106 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1107 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1108 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1109 RemoveEntryList(ServiceEntry
);
1110 ExFreePool(CurrentService
);
1112 ServiceEntry
= ServiceListHead
.Flink
;
1115 DPRINT("IoDestroyDriverList() done\n");
1117 return(STATUS_SUCCESS
);
1120 VOID STATIC INIT_FUNCTION
1121 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1125 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1127 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1132 * IopInitializeBuiltinDriver
1134 * Initialize a driver that is already loaded in memory.
1137 NTSTATUS FASTCALL INIT_FUNCTION
1138 IopInitializeBuiltinDriver(
1139 PDEVICE_NODE ModuleDeviceNode
,
1140 PVOID ModuleLoadBase
,
1144 PMODULE_OBJECT ModuleObject
;
1145 PDEVICE_NODE DeviceNode
;
1146 PDRIVER_OBJECT DriverObject
;
1148 CHAR TextBuffer
[256];
1149 PCHAR FileNameWithoutPath
;
1150 LPWSTR FileExtension
;
1152 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1153 FileName
, ModuleLoadBase
, ModuleLength
);
1156 * Display 'Initializing XXX...' message
1159 sprintf(TextBuffer
, "Initializing %s...\n", FileName
);
1160 HalDisplayString(TextBuffer
);
1163 * Determine the right device object
1166 if (ModuleDeviceNode
== NULL
)
1168 /* Use IopRootDeviceNode for now */
1169 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1170 if (!NT_SUCCESS(Status
))
1172 CPRINT("Driver load failed, status (%x)\n", Status
);
1177 DeviceNode
= ModuleDeviceNode
;
1181 * Generate filename without path (not needed by freeldr)
1184 FileNameWithoutPath
= strrchr(FileName
, '\\');
1185 if (FileNameWithoutPath
== NULL
)
1187 FileNameWithoutPath
= FileName
;
1194 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1195 FileNameWithoutPath
);
1196 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1198 if (!NT_SUCCESS(Status
))
1200 if (ModuleDeviceNode
== NULL
)
1201 IopFreeDeviceNode(DeviceNode
);
1202 CPRINT("Driver load failed, status (%x)\n", Status
);
1207 KDB_SYMBOLFILE_HOOK(FileName
);
1210 * Strip the file extension from ServiceName
1213 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1214 if (FileExtension
!= NULL
)
1216 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1217 FileExtension
[0] = 0;
1221 * Initialize the driver
1224 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1225 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1227 if (!NT_SUCCESS(Status
))
1229 if (ModuleDeviceNode
== NULL
)
1230 IopFreeDeviceNode(DeviceNode
);
1231 CPRINT("Driver load failed, status (%x)\n", Status
);
1235 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1241 * IopInitializeBootDrivers
1243 * Initialize boot drivers and free memory for boot files.
1253 IopInitializeBootDrivers(VOID
)
1255 ULONG BootDriverCount
;
1261 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1263 UNICODE_STRING DriverName
;
1266 DPRINT("IopInitializeBootDrivers()\n");
1268 BootDriverCount
= 0;
1269 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1271 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1272 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1273 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1274 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1275 Extension
= strrchr(ModuleName
, '.');
1276 if (Extension
== NULL
)
1279 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1281 /* Process symbols for *.exe and *.dll */
1282 KDB_SYMBOLFILE_HOOK(ModuleName
);
1284 /* Log *.exe and *.dll files */
1285 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1286 IopBootLog(&DriverName
, TRUE
);
1287 RtlFreeUnicodeString(&DriverName
);
1289 else if (!_stricmp(Extension
, ".sys"))
1291 /* Initialize and log boot start driver */
1294 Status
= IopInitializeBuiltinDriver(NULL
,
1298 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1299 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1300 RtlFreeUnicodeString(&DriverName
);
1307 * Free memory for all boot files, except ntoskrnl.exe.
1309 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1311 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1312 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1315 KeLoaderBlock
.ModsCount
= 0;
1317 if (BootDriverCount
== 0)
1319 DbgPrint("No boot drivers available.\n");
1324 static INIT_FUNCTION NTSTATUS
1325 IopLoadDriver(PSERVICE Service
)
1327 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1329 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
);
1330 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1331 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1332 if (!NT_SUCCESS(Status
))
1334 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1336 if (Service
->ErrorControl
== 1)
1340 else if (Service
->ErrorControl
== 2)
1342 if (IsLastKnownGood
== FALSE
)
1344 /* Boot last known good configuration */
1347 else if (Service
->ErrorControl
== 3)
1349 if (IsLastKnownGood
== FALSE
)
1351 /* Boot last known good configuration */
1365 * IopInitializeSystemDrivers
1367 * Load drivers marked as system start.
1377 IopInitializeSystemDrivers(VOID
)
1379 PLIST_ENTRY GroupEntry
;
1380 PLIST_ENTRY ServiceEntry
;
1381 PSERVICE_GROUP CurrentGroup
;
1382 PSERVICE CurrentService
;
1386 DPRINT("IopInitializeSystemDrivers()\n");
1388 GroupEntry
= GroupListHead
.Flink
;
1389 while (GroupEntry
!= &GroupListHead
)
1391 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1393 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1395 /* Load all drivers with a valid tag */
1396 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1398 ServiceEntry
= ServiceListHead
.Flink
;
1399 while (ServiceEntry
!= &ServiceListHead
)
1401 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1403 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1404 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1405 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1406 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1408 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1409 Status
= IopLoadDriver(CurrentService
);
1411 ServiceEntry
= ServiceEntry
->Flink
;
1415 /* Load all drivers without a tag or with an invalid tag */
1416 ServiceEntry
= ServiceListHead
.Flink
;
1417 while (ServiceEntry
!= &ServiceListHead
)
1419 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1420 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1421 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1422 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1424 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1426 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1431 if (i
>= CurrentGroup
->TagCount
)
1433 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1434 Status
= IopLoadDriver(CurrentService
);
1437 ServiceEntry
= ServiceEntry
->Flink
;
1440 GroupEntry
= GroupEntry
->Flink
;
1443 DPRINT("IopInitializeSystemDrivers() done\n");
1449 * Unloads a device driver.
1453 * Name of the service to unload (registry key).
1456 * Whether to unload Plug & Plug or only legacy drivers. If this
1457 * parameter is set to FALSE, the routine will unload only legacy
1464 * Guard the whole function by SEH.
1468 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1470 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1471 UNICODE_STRING ImagePath
;
1472 UNICODE_STRING ServiceName
;
1473 UNICODE_STRING ObjectName
;
1474 PDRIVER_OBJECT DriverObject
;
1475 PMODULE_OBJECT ModuleObject
;
1479 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1482 * Get the service name from the registry key name
1485 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1487 Start
= DriverServiceName
->Buffer
;
1491 RtlInitUnicodeString(&ServiceName
, Start
);
1494 * Construct the driver object name
1497 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1498 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1499 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1500 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1501 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1502 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1505 * Find the driver object
1508 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1509 KernelMode
, 0, (PVOID
*)&DriverObject
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1518 * Free the buffer for driver object name
1521 ExFreePool(ObjectName
.Buffer
);
1524 * Get path of service...
1527 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1529 RtlInitUnicodeString(&ImagePath
, NULL
);
1531 QueryTable
[0].Name
= L
"ImagePath";
1532 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1533 QueryTable
[0].EntryContext
= &ImagePath
;
1535 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1536 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1538 if (!NT_SUCCESS(Status
))
1540 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1545 * Normalize the image path for all later processing.
1548 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1550 if (!NT_SUCCESS(Status
))
1552 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1557 * ... and check if it's loaded
1560 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1561 if (ModuleObject
== NULL
)
1563 return STATUS_UNSUCCESSFUL
;
1567 * Free the service path
1570 ExFreePool(ImagePath
.Buffer
);
1573 * Unload the module and release the references to the device object
1576 if (DriverObject
->DriverUnload
)
1577 (*DriverObject
->DriverUnload
)(DriverObject
);
1578 ObDereferenceObject(DriverObject
);
1579 ObDereferenceObject(DriverObject
);
1580 LdrUnloadModule(ModuleObject
);
1582 return STATUS_SUCCESS
;
1586 IopMarkLastReinitializeDriver(VOID
)
1590 KeAcquireSpinLock(&DriverReinitListLock
,
1593 if (IsListEmpty(&DriverReinitListHead
))
1595 DriverReinitTailEntry
= NULL
;
1599 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1602 KeReleaseSpinLock(&DriverReinitListLock
,
1608 IopReinitializeDrivers(VOID
)
1610 PDRIVER_REINIT_ITEM ReinitItem
;
1614 KeAcquireSpinLock(&DriverReinitListLock
,
1617 if (DriverReinitTailEntry
== NULL
)
1619 KeReleaseSpinLock(&DriverReinitListLock
,
1624 KeReleaseSpinLock(&DriverReinitListLock
,
1629 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1630 &DriverReinitListLock
);
1634 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1636 /* Increment reinitialization counter */
1637 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1639 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1640 ReinitItem
->Context
,
1641 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1645 if (Entry
== DriverReinitTailEntry
)
1650 /* PUBLIC FUNCTIONS ***********************************************************/
1659 IN PUNICODE_STRING DriverName
, OPTIONAL
1660 IN PDRIVER_INITIALIZE InitializationFunction
1663 WCHAR NameBuffer
[100];
1665 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1667 OBJECT_ATTRIBUTES ObjectAttributes
;
1669 PDRIVER_OBJECT DriverObject
;
1670 UNICODE_STRING ServiceKeyName
;
1674 /* First, create a unique name for the driver if we don't have one */
1677 /* Create a random name and set up the string*/
1678 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1679 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1680 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1681 LocalDriverName
.Buffer
= NameBuffer
;
1685 /* So we can avoid another code path, use a local var */
1686 LocalDriverName
= *DriverName
;
1689 /* Initialize the Attributes */
1690 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1691 InitializeObjectAttributes(&ObjectAttributes
,
1693 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1697 /* Create the Object */
1698 Status
= ObCreateObject(KernelMode
,
1706 (PVOID
*)&DriverObject
);
1708 /* Return on failure */
1709 if (!NT_SUCCESS(Status
)) return Status
;
1711 /* Set up the Object */
1712 RtlZeroMemory(DriverObject
, ObjectSize
);
1713 DriverObject
->Type
= IO_TYPE_DRIVER
;
1714 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1715 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1716 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1717 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1718 DriverObject
->DriverInit
= InitializationFunction
;
1720 /* Invalidate all Major Functions */
1721 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1723 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1726 /* Set up the Service Key Name */
1727 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1728 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1729 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1730 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1731 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1732 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1734 /* Also store it in the Driver Object. This is a bit of a hack. */
1735 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1737 /* Add the Object and get its handle */
1738 Status
= ObInsertObject(DriverObject
,
1745 /* Return on Failure */
1746 if (!NT_SUCCESS(Status
)) return Status
;
1748 /* Now reference it */
1749 Status
= ObReferenceObjectByHandle(hDriver
,
1753 (PVOID
*)&DriverObject
,
1757 /* Finally, call its init function */
1758 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1760 if (!NT_SUCCESS(Status
)) {
1761 /* If it didn't work, then kill the object */
1762 ObMakeTemporaryObject(DriverObject
);
1763 ObDereferenceObject(DriverObject
);
1766 /* Return the Status */
1776 IN PDRIVER_OBJECT DriverObject
1779 /* Simply derefence the Object */
1780 ObDereferenceObject(DriverObject
);
1787 * Loads a device driver.
1791 * Name of the service to load (registry key).
1801 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1803 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1804 UNICODE_STRING ImagePath
;
1805 UNICODE_STRING ServiceName
;
1806 UNICODE_STRING CapturedDriverServiceName
;
1807 KPROCESSOR_MODE PreviousMode
;
1810 PDEVICE_NODE DeviceNode
;
1811 PMODULE_OBJECT ModuleObject
;
1812 PDRIVER_OBJECT DriverObject
;
1817 PreviousMode
= KeGetPreviousMode();
1820 * Check security privileges
1823 /* FIXME: Uncomment when privileges will be correctly implemented. */
1825 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1827 DPRINT("Privilege not held\n");
1828 return STATUS_PRIVILEGE_NOT_HELD
;
1832 Status
= RtlCaptureUnicodeString(&CapturedDriverServiceName
,
1837 if (!NT_SUCCESS(Status
))
1842 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1844 RtlInitUnicodeString(&ImagePath
, NULL
);
1847 * Get the service name from the registry key name.
1849 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1851 ServiceName
= CapturedDriverServiceName
;
1852 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1853 while (CapturedDriverServiceName
.Buffer
!= cur
)
1857 ServiceName
.Buffer
= cur
+ 1;
1858 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1859 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1860 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1870 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1872 RtlInitUnicodeString(&ImagePath
, NULL
);
1874 QueryTable
[0].Name
= L
"Type";
1875 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1876 QueryTable
[0].EntryContext
= &Type
;
1878 QueryTable
[1].Name
= L
"ImagePath";
1879 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1880 QueryTable
[1].EntryContext
= &ImagePath
;
1882 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1883 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1885 if (!NT_SUCCESS(Status
))
1887 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1888 ExFreePool(ImagePath
.Buffer
);
1889 goto ReleaseCapturedString
;
1893 * Normalize the image path for all later processing.
1896 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1898 if (!NT_SUCCESS(Status
))
1900 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1901 goto ReleaseCapturedString
;
1904 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1905 DPRINT("Type: %lx\n", Type
);
1908 * See, if the driver module isn't already loaded
1911 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1912 if (ModuleObject
!= NULL
)
1914 DPRINT("Image already loaded\n");
1915 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1916 goto ReleaseCapturedString
;
1920 * Create device node
1923 /* Use IopRootDeviceNode for now */
1924 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1926 if (!NT_SUCCESS(Status
))
1928 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1929 goto ReleaseCapturedString
;
1933 * Load the driver module
1936 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1938 if (!NT_SUCCESS(Status
))
1940 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1941 IopFreeDeviceNode(DeviceNode
);
1942 goto ReleaseCapturedString
;
1946 * Set a service name for the device node
1949 RtlpCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
, NonPagedPool
);
1952 * Initialize the driver module
1955 Status
= IopInitializeDriverModule(
1958 &DeviceNode
->ServiceName
,
1959 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1960 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1963 if (!NT_SUCCESS(Status
))
1965 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1966 LdrUnloadModule(ModuleObject
);
1967 IopFreeDeviceNode(DeviceNode
);
1968 goto ReleaseCapturedString
;
1971 IopInitializeDevice(DeviceNode
, DriverObject
);
1973 ReleaseCapturedString
:
1974 RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1984 * Unloads a legacy device driver.
1988 * Name of the service to unload (registry key).
1998 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2000 return IopUnloadDriver(DriverServiceName
, FALSE
);
2004 * IoRegisterDriverReinitialization
2011 IoRegisterDriverReinitialization(
2012 PDRIVER_OBJECT DriverObject
,
2013 PDRIVER_REINITIALIZE ReinitRoutine
,
2016 PDRIVER_REINIT_ITEM ReinitItem
;
2018 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2019 if (ReinitItem
== NULL
)
2022 ReinitItem
->DriverObject
= DriverObject
;
2023 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2024 ReinitItem
->Context
= Context
;
2026 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2028 ExInterlockedInsertTailList(
2029 &DriverReinitListHead
,
2030 &ReinitItem
->ItemEntry
,
2031 &DriverReinitListLock
);
2039 IoRegisterBootDriverReinitialization(
2040 IN PDRIVER_OBJECT DriverObject
,
2041 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2045 PDRIVER_REINIT_ITEM ReinitItem
;
2047 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2048 if (ReinitItem
== NULL
)
2051 ReinitItem
->DriverObject
= DriverObject
;
2052 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2053 ReinitItem
->Context
= Context
;
2055 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2057 ExInterlockedInsertTailList(
2058 &DriverBootReinitListHead
,
2059 &ReinitItem
->ItemEntry
,
2060 &DriverReinitListLock
);
2064 * IoAllocateDriverObjectExtension
2071 IoAllocateDriverObjectExtension(
2072 PDRIVER_OBJECT DriverObject
,
2073 PVOID ClientIdentificationAddress
,
2074 ULONG DriverObjectExtensionSize
,
2075 PVOID
*DriverObjectExtension
)
2078 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2079 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2081 NewDriverExtension
= ExAllocatePoolWithTag(
2083 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2084 DriverObjectExtensionSize
,
2085 TAG_DRIVER_EXTENSION
);
2087 if (NewDriverExtension
== NULL
)
2089 return STATUS_INSUFFICIENT_RESOURCES
;
2092 OldIrql
= KeRaiseIrqlToDpcLevel();
2094 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2095 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2097 for (DriverExtensions
= DriverObject
->DriverSection
;
2098 DriverExtensions
!= NULL
;
2099 DriverExtensions
= DriverExtensions
->Link
)
2101 if (DriverExtensions
->ClientIdentificationAddress
==
2102 ClientIdentificationAddress
)
2104 KfLowerIrql(OldIrql
);
2105 return STATUS_OBJECT_NAME_COLLISION
;
2109 DriverObject
->DriverSection
= NewDriverExtension
;
2111 KfLowerIrql(OldIrql
);
2113 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2115 return STATUS_SUCCESS
;
2119 * IoGetDriverObjectExtension
2126 IoGetDriverObjectExtension(
2127 PDRIVER_OBJECT DriverObject
,
2128 PVOID ClientIdentificationAddress
)
2131 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2133 OldIrql
= KeRaiseIrqlToDpcLevel();
2135 for (DriverExtensions
= DriverObject
->DriverSection
;
2136 DriverExtensions
!= NULL
&&
2137 DriverExtensions
->ClientIdentificationAddress
!=
2138 ClientIdentificationAddress
;
2139 DriverExtensions
= DriverExtensions
->Link
)
2142 KfLowerIrql(OldIrql
);
2144 if (DriverExtensions
== NULL
)
2147 return &DriverExtensions
->Extension
;