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 PLDR_DATA_TABLE_ENTRY
*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 DriverName
.Buffer
= NameBuffer
;
174 DriverName
.Length
= 0;
175 DriverName
.MaximumLength
= sizeof(NameBuffer
);
177 if (FileSystem
== TRUE
)
178 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
180 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
181 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
183 DPRINT("Driver name: '%wZ'\n", &DriverName
);
185 /* Initialize ObjectAttributes for driver object */
186 InitializeObjectAttributes(
189 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
193 /* Open driver object */
194 Status
= ObReferenceObjectByName(
197 NULL
, /* PassedAccessState */
198 0, /* DesiredAccess */
201 NULL
, /* ParseContext */
204 if (!NT_SUCCESS(Status
))
207 *DriverObject
= Object
;
209 return STATUS_SUCCESS
;
213 IopCreateDriverObject(
214 PDRIVER_OBJECT
*DriverObject
,
215 PUNICODE_STRING ServiceName
,
216 ULONG CreateAttributes
,
218 PVOID DriverImageStart
,
219 ULONG DriverImageSize
)
221 PDRIVER_OBJECT Object
;
222 WCHAR NameBuffer
[MAX_PATH
];
223 UNICODE_STRING DriverName
;
224 OBJECT_ATTRIBUTES ObjectAttributes
;
229 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
230 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
232 *DriverObject
= NULL
;
234 /* Create ModuleName string */
235 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
237 if (FileSystem
== TRUE
)
238 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
240 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
241 wcscat(NameBuffer
, ServiceName
->Buffer
);
243 RtlInitUnicodeString(&DriverName
, NameBuffer
);
244 DPRINT("Driver name: '%wZ'\n", &DriverName
);
246 Buffer
= (PWSTR
)ExAllocatePool(PagedPool
, DriverName
.Length
+ sizeof(WCHAR
));
247 /* If we don't success, it is not a problem. Our driver
248 * object will not have associated driver name... */
252 RtlInitUnicodeString(&DriverName
, NULL
);
255 /* Initialize ObjectAttributes for driver object */
256 InitializeObjectAttributes(
259 CreateAttributes
| OBJ_PERMANENT
,
263 /* Create driver object */
264 Status
= ObCreateObject(
270 sizeof(DRIVER_OBJECT
),
275 if (!NT_SUCCESS(Status
))
280 Status
= ObInsertObject(Object
,
286 if (!NT_SUCCESS(Status
))
291 /* Create driver extension */
292 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
293 ExAllocatePoolWithTag(
295 sizeof(DRIVER_EXTENSION
),
296 TAG_DRIVER_EXTENSION
);
298 if (Object
->DriverExtension
== NULL
)
300 return STATUS_NO_MEMORY
;
303 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
305 Object
->Type
= IO_TYPE_DRIVER
;
307 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
308 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
310 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
312 Object
->DriverStart
= DriverImageStart
;
313 Object
->DriverSize
= DriverImageSize
;
316 if (!Object
->DriverName
.Buffer
)
318 Object
->DriverName
.Buffer
= Buffer
;
319 Object
->DriverName
.Length
= DriverName
.Length
;
320 Object
->DriverName
.MaximumLength
= DriverName
.Length
+ sizeof(WCHAR
);
321 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
322 Object
->DriverName
.Buffer
[Object
->DriverName
.Length
/ sizeof(WCHAR
)] = L
'\0';
328 *DriverObject
= Object
;
330 return STATUS_SUCCESS
;
334 * IopDisplayLoadingMessage
336 * Display 'Loading XXX...' message.
342 IopDisplayLoadingMessage(PVOID ServiceName
,
345 CHAR TextBuffer
[256];
346 if (SetupMode
) return;
349 sprintf(TextBuffer
, "Loading %S...\n", (PWCHAR
)ServiceName
);
353 sprintf(TextBuffer
, "Loading %s...\n", (PCHAR
)ServiceName
);
355 HalDisplayString(TextBuffer
);
359 * IopNormalizeImagePath
361 * Normalize an image path to contain complete path.
365 * The input path and on exit the result path. ImagePath.Buffer
366 * must be allocated by ExAllocatePool on input. Caller is responsible
367 * for freeing the buffer when it's no longer needed.
370 * Name of the service that ImagePath belongs to.
376 * The input image path isn't freed on error.
380 IopNormalizeImagePath(
381 IN OUT PUNICODE_STRING ImagePath
,
382 IN PUNICODE_STRING ServiceName
)
384 UNICODE_STRING InputImagePath
;
389 sizeof(UNICODE_STRING
));
391 if (InputImagePath
.Length
== 0)
393 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
394 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
395 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
396 if (ImagePath
->Buffer
== NULL
)
397 return STATUS_NO_MEMORY
;
399 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
400 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
401 wcscat(ImagePath
->Buffer
, L
".sys");
403 if (InputImagePath
.Buffer
[0] != L
'\\')
405 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
406 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
407 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
408 if (ImagePath
->Buffer
== NULL
)
409 return STATUS_NO_MEMORY
;
411 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
412 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
413 ExFreePool(InputImagePath
.Buffer
);
416 return STATUS_SUCCESS
;
420 * IopLoadServiceModule
422 * Load a module specified by registry settings for service.
426 * Name of the service to load.
433 IopLoadServiceModule(
434 IN PUNICODE_STRING ServiceName
,
435 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
437 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
439 UNICODE_STRING ServiceImagePath
;
442 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
445 * Get information about the service.
448 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
450 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
452 QueryTable
[0].Name
= L
"Start";
453 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
454 QueryTable
[0].EntryContext
= &ServiceStart
;
456 QueryTable
[1].Name
= L
"ImagePath";
457 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
458 QueryTable
[1].EntryContext
= &ServiceImagePath
;
460 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
461 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
463 if (!NT_SUCCESS(Status
))
465 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
469 IopDisplayLoadingMessage(ServiceName
->Buffer
, TRUE
);
472 * Normalize the image path for all later processing.
475 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
477 if (!NT_SUCCESS(Status
))
479 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
487 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
489 if (*ModuleObject
== NULL
)
491 Status
= STATUS_UNSUCCESSFUL
;
494 * Special case for boot modules that were loaded by boot loader.
497 if (ServiceStart
== 0)
500 CHAR SearchName
[256];
502 PLOADER_MODULE KeLoaderModules
=
503 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
507 * Improve this searching algorithm by using the image name
508 * stored in registry entry ImageName and use the whole path
509 * (requires change in FreeLoader).
512 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
513 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
515 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
516 if (!_stricmp(ModuleName
, SearchName
))
518 DPRINT("Initializing boot module\n");
520 /* Tell, that the module is already loaded */
521 KeLoaderModules
[i
].Reserved
= 1;
523 Status
= LdrProcessModule(
524 (PVOID
)KeLoaderModules
[i
].ModStart
,
528 KDB_SYMBOLFILE_HOOK(SearchName
);
536 * Case for rest of the drivers (except disabled)
539 else if (ServiceStart
< 4)
541 DPRINT("Loading module\n");
542 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
547 DPRINT("Module already loaded\n");
548 Status
= STATUS_IMAGE_ALREADY_LOADED
;
551 ExFreePool(ServiceImagePath
.Buffer
);
554 * Now check if the module was loaded successfully.
557 if (!NT_SUCCESS(Status
))
559 DPRINT("Module loading failed (Status %x)\n", Status
);
562 DPRINT("Module loading (Status %x)\n", Status
);
568 * IopInitializeDriverModule
570 * Initalize a loaded driver.
574 * Pointer to device node.
577 * Module object representing the driver. It can be retrieve by
578 * IopLoadServiceModule.
581 * Name of the service (as in registry).
584 * Set to TRUE for file system drivers.
587 * On successful return this contains the driver object representing
592 IopInitializeDriverModule(
593 IN PDEVICE_NODE DeviceNode
,
594 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
595 IN PUNICODE_STRING ServiceName
,
596 IN BOOLEAN FileSystemDriver
,
597 OUT PDRIVER_OBJECT
*DriverObject
)
599 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
600 UNICODE_STRING RegistryKey
;
601 PDRIVER_INITIALIZE DriverEntry
;
604 DriverEntry
= ModuleObject
->EntryPoint
;
606 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
608 RegistryKey
.Length
= 0;
609 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
610 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
611 if (RegistryKey
.Buffer
== NULL
)
613 return STATUS_INSUFFICIENT_RESOURCES
;
615 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
616 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
620 RtlInitUnicodeString(&RegistryKey
, NULL
);
623 Status
= IopCreateDriverObject(
628 ModuleObject
->DllBase
,
629 ModuleObject
->SizeOfImage
);
631 if (!NT_SUCCESS(Status
))
633 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
637 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
638 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
640 IopMarkLastReinitializeDriver();
642 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
644 RtlFreeUnicodeString(&RegistryKey
);
646 if (!NT_SUCCESS(Status
))
648 ObMakeTemporaryObject(*DriverObject
);
649 ObDereferenceObject(*DriverObject
);
653 IopReinitializeDrivers();
655 return STATUS_SUCCESS
;
659 * IopAttachFilterDriversCallback
661 * Internal routine used by IopAttachFilterDrivers.
665 IopAttachFilterDriversCallback(
673 PDEVICE_NODE DeviceNode
= Context
;
674 UNICODE_STRING ServiceName
;
676 PLDR_DATA_TABLE_ENTRY ModuleObject
;
677 PDRIVER_OBJECT DriverObject
;
680 for (Filters
= ValueData
;
681 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
683 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
685 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
686 ServiceName
.Buffer
= Filters
;
687 ServiceName
.MaximumLength
=
688 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
690 /* Load and initialize the filter driver */
691 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
692 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
694 if (!NT_SUCCESS(Status
))
697 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
698 FALSE
, &DriverObject
);
699 if (!NT_SUCCESS(Status
))
704 /* get existing DriverObject pointer */
705 Status
= IopGetDriverObject(
709 if (!NT_SUCCESS(Status
))
713 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
714 if (!NT_SUCCESS(Status
))
718 return STATUS_SUCCESS
;
722 * IopAttachFilterDrivers
724 * Load filter drivers for specified device node.
728 * Set to TRUE for loading lower level filters or FALSE for upper
733 IopAttachFilterDrivers(
734 PDEVICE_NODE DeviceNode
,
737 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
739 UNICODE_STRING Class
;
740 WCHAR ClassBuffer
[40];
744 * First load the device filters
747 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
749 QueryTable
[0].Name
= L
"LowerFilters";
751 QueryTable
[0].Name
= L
"UpperFilters";
752 QueryTable
[0].EntryContext
= NULL
;
753 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
754 QueryTable
[1].QueryRoutine
= NULL
;
755 QueryTable
[1].Name
= NULL
;
757 KeyBuffer
= ExAllocatePool(
759 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
760 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
761 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
763 RtlQueryRegistryValues(
764 RTL_REGISTRY_ABSOLUTE
,
771 * Now get the class GUID
775 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
776 Class
.Buffer
= ClassBuffer
;
777 QueryTable
[0].QueryRoutine
= NULL
;
778 QueryTable
[0].Name
= L
"ClassGUID";
779 QueryTable
[0].EntryContext
= &Class
;
780 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
782 Status
= RtlQueryRegistryValues(
783 RTL_REGISTRY_ABSOLUTE
,
789 ExFreePool(KeyBuffer
);
792 * Load the class filter driver
795 if (NT_SUCCESS(Status
))
797 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
799 QueryTable
[0].Name
= L
"LowerFilters";
801 QueryTable
[0].Name
= L
"UpperFilters";
802 QueryTable
[0].EntryContext
= NULL
;
803 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
805 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
806 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
807 wcscat(KeyBuffer
, ClassBuffer
);
809 RtlQueryRegistryValues(
810 RTL_REGISTRY_ABSOLUTE
,
816 ExFreePool(KeyBuffer
);
819 return STATUS_SUCCESS
;
822 static NTSTATUS STDCALL
823 IopGetGroupOrderList(PWSTR ValueName
,
830 PSERVICE_GROUP Group
;
832 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
833 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
835 if (ValueType
== REG_BINARY
&&
837 ValueLength
>= sizeof(DWORD
) &&
838 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
840 Group
= (PSERVICE_GROUP
)Context
;
841 Group
->TagCount
= ((PULONG
)ValueData
)[0];
842 if (Group
->TagCount
> 0)
844 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
846 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
847 if (Group
->TagArray
== NULL
)
850 return STATUS_INSUFFICIENT_RESOURCES
;
852 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
857 return STATUS_UNSUCCESSFUL
;
861 return STATUS_SUCCESS
;
864 static NTSTATUS STDCALL
865 IopCreateGroupListEntry(PWSTR ValueName
,
872 PSERVICE_GROUP Group
;
873 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
877 if (ValueType
== REG_SZ
)
879 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
881 Group
= ExAllocatePool(NonPagedPool
,
882 sizeof(SERVICE_GROUP
));
885 return(STATUS_INSUFFICIENT_RESOURCES
);
888 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
890 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
893 return(STATUS_INSUFFICIENT_RESOURCES
);
896 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
897 QueryTable
[0].Name
= (PWSTR
)ValueData
;
898 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
900 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
905 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
907 InsertTailList(&GroupListHead
,
908 &Group
->GroupListEntry
);
911 return(STATUS_SUCCESS
);
915 static NTSTATUS STDCALL
916 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
918 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
922 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
924 /* Allocate service entry */
925 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
928 DPRINT1("ExAllocatePool() failed\n");
929 return(STATUS_INSUFFICIENT_RESOURCES
);
931 RtlZeroMemory(Service
, sizeof(SERVICE
));
933 /* Get service data */
934 RtlZeroMemory(&QueryTable
,
937 QueryTable
[0].Name
= L
"Start";
938 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
939 QueryTable
[0].EntryContext
= &Service
->Start
;
941 QueryTable
[1].Name
= L
"Type";
942 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
943 QueryTable
[1].EntryContext
= &Service
->Type
;
945 QueryTable
[2].Name
= L
"ErrorControl";
946 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
947 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
949 QueryTable
[3].Name
= L
"Group";
950 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
951 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
953 QueryTable
[4].Name
= L
"ImagePath";
954 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
955 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
957 QueryTable
[5].Name
= L
"Tag";
958 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
959 QueryTable
[5].EntryContext
= &Service
->Tag
;
961 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
966 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
969 * If something goes wrong during RtlQueryRegistryValues
970 * it'll just drop everything on the floor and return,
971 * so you have to check if the buffers were filled.
972 * Luckily we zerofilled the Service.
974 if (Service
->ServiceGroup
.Buffer
)
976 ExFreePool(Service
->ServiceGroup
.Buffer
);
978 if (Service
->ImagePath
.Buffer
)
980 ExFreePool(Service
->ImagePath
.Buffer
);
986 /* Copy service name */
987 Service
->ServiceName
.Length
= ServiceName
->Length
;
988 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
989 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
990 Service
->ServiceName
.MaximumLength
);
991 RtlCopyMemory(Service
->ServiceName
.Buffer
,
993 ServiceName
->Length
);
994 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
996 /* Build registry path */
997 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
998 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
999 MAX_PATH
* sizeof(WCHAR
));
1000 wcscpy(Service
->RegistryPath
.Buffer
,
1001 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1002 wcscat(Service
->RegistryPath
.Buffer
,
1003 Service
->ServiceName
.Buffer
);
1004 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
1006 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
1007 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
1008 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
1009 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
1010 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1011 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
1013 /* Append service entry */
1014 InsertTailList(&ServiceListHead
,
1015 &Service
->ServiceListEntry
);
1017 return(STATUS_SUCCESS
);
1021 NTSTATUS INIT_FUNCTION
1022 IoCreateDriverList(VOID
)
1024 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1025 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
1026 OBJECT_ATTRIBUTES ObjectAttributes
;
1027 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1028 UNICODE_STRING SubKeyName
;
1033 ULONG KeyInfoLength
= 0;
1034 ULONG ReturnedLength
;
1036 DPRINT("IoCreateDriverList() called\n");
1038 /* Initialize basic variables */
1039 InitializeListHead(&GroupListHead
);
1040 InitializeListHead(&ServiceListHead
);
1042 /* Build group order list */
1043 RtlZeroMemory(&QueryTable
,
1044 sizeof(QueryTable
));
1046 QueryTable
[0].Name
= L
"List";
1047 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1049 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1050 L
"ServiceGroupOrder",
1054 if (!NT_SUCCESS(Status
))
1057 /* Enumerate services and create the service list */
1058 InitializeObjectAttributes(&ObjectAttributes
,
1060 OBJ_CASE_INSENSITIVE
,
1064 Status
= ZwOpenKey(&KeyHandle
,
1065 KEY_ENUMERATE_SUB_KEYS
,
1067 if (!NT_SUCCESS(Status
))
1072 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1073 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1074 if (KeyInfo
== NULL
)
1077 return(STATUS_INSUFFICIENT_RESOURCES
);
1083 Status
= ZwEnumerateKey(KeyHandle
,
1085 KeyBasicInformation
,
1089 if (NT_SUCCESS(Status
))
1091 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1094 SubKeyName
.Length
= KeyInfo
->NameLength
;
1095 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1096 SubKeyName
.Buffer
= KeyInfo
->Name
;
1097 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1099 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1100 IopCreateServiceListEntry(&SubKeyName
);
1104 if (!NT_SUCCESS(Status
))
1110 ExFreePool(KeyInfo
);
1113 DPRINT("IoCreateDriverList() done\n");
1115 return(STATUS_SUCCESS
);
1118 NTSTATUS INIT_FUNCTION
1119 IoDestroyDriverList(VOID
)
1121 PLIST_ENTRY GroupEntry
;
1122 PLIST_ENTRY ServiceEntry
;
1123 PSERVICE_GROUP CurrentGroup
;
1124 PSERVICE CurrentService
;
1126 DPRINT("IoDestroyDriverList() called\n");
1128 /* Destroy group list */
1129 GroupEntry
= GroupListHead
.Flink
;
1130 while (GroupEntry
!= &GroupListHead
)
1132 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1134 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1135 RemoveEntryList(GroupEntry
);
1136 if (CurrentGroup
->TagArray
)
1138 ExFreePool(CurrentGroup
->TagArray
);
1140 ExFreePool(CurrentGroup
);
1142 GroupEntry
= GroupListHead
.Flink
;
1145 /* Destroy service list */
1146 ServiceEntry
= ServiceListHead
.Flink
;
1147 while (ServiceEntry
!= &ServiceListHead
)
1149 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1151 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1152 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1153 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1154 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1155 RemoveEntryList(ServiceEntry
);
1156 ExFreePool(CurrentService
);
1158 ServiceEntry
= ServiceListHead
.Flink
;
1161 DPRINT("IoDestroyDriverList() done\n");
1163 return(STATUS_SUCCESS
);
1166 VOID STATIC INIT_FUNCTION
1167 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1171 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1173 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1178 * IopInitializeBuiltinDriver
1180 * Initialize a driver that is already loaded in memory.
1183 NTSTATUS FASTCALL INIT_FUNCTION
1184 IopInitializeBuiltinDriver(
1185 PDEVICE_NODE ModuleDeviceNode
,
1186 PVOID ModuleLoadBase
,
1190 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1191 PDEVICE_NODE DeviceNode
;
1192 PDRIVER_OBJECT DriverObject
;
1194 PCHAR FileNameWithoutPath
;
1195 LPWSTR FileExtension
;
1197 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1198 FileName
, ModuleLoadBase
, ModuleLength
);
1201 * Display 'Loading XXX...' message
1203 IopDisplayLoadingMessage(FileName
, FALSE
);
1206 * Determine the right device object
1209 if (ModuleDeviceNode
== NULL
)
1211 /* Use IopRootDeviceNode for now */
1212 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1213 if (!NT_SUCCESS(Status
))
1215 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1220 DeviceNode
= ModuleDeviceNode
;
1224 * Generate filename without path (not needed by freeldr)
1227 FileNameWithoutPath
= strrchr(FileName
, '\\');
1228 if (FileNameWithoutPath
== NULL
)
1230 FileNameWithoutPath
= FileName
;
1237 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1238 FileNameWithoutPath
);
1239 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1241 if (!NT_SUCCESS(Status
))
1243 if (ModuleDeviceNode
== NULL
)
1244 IopFreeDeviceNode(DeviceNode
);
1245 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1250 KDB_SYMBOLFILE_HOOK(FileName
);
1253 * Strip the file extension from ServiceName
1256 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1257 if (FileExtension
!= NULL
)
1259 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1260 FileExtension
[0] = 0;
1264 * Initialize the driver
1267 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1268 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1270 if (!NT_SUCCESS(Status
))
1272 if (ModuleDeviceNode
== NULL
)
1273 IopFreeDeviceNode(DeviceNode
);
1274 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1278 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1279 if (NT_SUCCESS(Status
))
1281 Status
= IopStartDevice(DeviceNode
);
1288 * IopInitializeBootDrivers
1290 * Initialize boot drivers and free memory for boot files.
1300 IopInitializeBootDrivers(VOID
)
1302 ULONG BootDriverCount
;
1308 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1310 UNICODE_STRING DriverName
;
1313 DPRINT("IopInitializeBootDrivers()\n");
1315 BootDriverCount
= 0;
1316 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1318 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1319 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1320 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1321 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1322 Extension
= strrchr(ModuleName
, '.');
1323 if (Extension
== NULL
)
1326 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1328 /* Process symbols for *.exe and *.dll */
1329 KDB_SYMBOLFILE_HOOK(ModuleName
);
1331 /* Log *.exe and *.dll files */
1332 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1333 IopBootLog(&DriverName
, TRUE
);
1334 RtlFreeUnicodeString(&DriverName
);
1336 else if (!_stricmp(Extension
, ".sys"))
1338 /* Initialize and log boot start driver */
1341 Status
= IopInitializeBuiltinDriver(NULL
,
1345 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1346 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1347 RtlFreeUnicodeString(&DriverName
);
1354 * Free memory for all boot files, except ntoskrnl.exe.
1356 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1358 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1359 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1362 KeLoaderBlock
.ModsCount
= 0;
1364 if (BootDriverCount
== 0)
1366 DbgPrint("No boot drivers available.\n");
1371 static INIT_FUNCTION NTSTATUS
1372 IopLoadDriver(PSERVICE Service
)
1374 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1376 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1377 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1378 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1379 if (!NT_SUCCESS(Status
))
1381 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1383 if (Service
->ErrorControl
== 1)
1387 else if (Service
->ErrorControl
== 2)
1389 if (IsLastKnownGood
== FALSE
)
1391 /* Boot last known good configuration */
1394 else if (Service
->ErrorControl
== 3)
1396 if (IsLastKnownGood
== FALSE
)
1398 /* Boot last known good configuration */
1412 * IopInitializeSystemDrivers
1414 * Load drivers marked as system start.
1424 IopInitializeSystemDrivers(VOID
)
1426 PLIST_ENTRY GroupEntry
;
1427 PLIST_ENTRY ServiceEntry
;
1428 PSERVICE_GROUP CurrentGroup
;
1429 PSERVICE CurrentService
;
1433 DPRINT("IopInitializeSystemDrivers()\n");
1435 GroupEntry
= GroupListHead
.Flink
;
1436 while (GroupEntry
!= &GroupListHead
)
1438 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1440 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1442 /* Load all drivers with a valid tag */
1443 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1445 ServiceEntry
= ServiceListHead
.Flink
;
1446 while (ServiceEntry
!= &ServiceListHead
)
1448 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1450 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1451 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1452 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1453 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1455 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1456 Status
= IopLoadDriver(CurrentService
);
1458 ServiceEntry
= ServiceEntry
->Flink
;
1462 /* Load all drivers without a tag or with an invalid tag */
1463 ServiceEntry
= ServiceListHead
.Flink
;
1464 while (ServiceEntry
!= &ServiceListHead
)
1466 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1467 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1468 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1469 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1471 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1473 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1478 if (i
>= CurrentGroup
->TagCount
)
1480 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1481 Status
= IopLoadDriver(CurrentService
);
1484 ServiceEntry
= ServiceEntry
->Flink
;
1487 GroupEntry
= GroupEntry
->Flink
;
1490 DPRINT("IopInitializeSystemDrivers() done\n");
1496 * Unloads a device driver.
1500 * Name of the service to unload (registry key).
1503 * Whether to unload Plug & Plug or only legacy drivers. If this
1504 * parameter is set to FALSE, the routine will unload only legacy
1511 * Guard the whole function by SEH.
1515 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1517 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1518 UNICODE_STRING ImagePath
;
1519 UNICODE_STRING ServiceName
;
1520 UNICODE_STRING ObjectName
;
1521 PDRIVER_OBJECT DriverObject
;
1522 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1526 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1531 * Get the service name from the registry key name
1534 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1536 Start
= DriverServiceName
->Buffer
;
1540 RtlInitUnicodeString(&ServiceName
, Start
);
1543 * Construct the driver object name
1546 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1547 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1548 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1549 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1550 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1551 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1554 * Find the driver object
1557 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1558 KernelMode
, 0, (PVOID
*)&DriverObject
);
1560 if (!NT_SUCCESS(Status
))
1562 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1567 * Free the buffer for driver object name
1570 ExFreePool(ObjectName
.Buffer
);
1573 * Get path of service...
1576 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1578 RtlInitUnicodeString(&ImagePath
, NULL
);
1580 QueryTable
[0].Name
= L
"ImagePath";
1581 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1582 QueryTable
[0].EntryContext
= &ImagePath
;
1584 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1585 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1587 if (!NT_SUCCESS(Status
))
1589 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1594 * Normalize the image path for all later processing.
1597 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1599 if (!NT_SUCCESS(Status
))
1601 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1606 * ... and check if it's loaded
1609 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1610 if (ModuleObject
== NULL
)
1612 return STATUS_UNSUCCESSFUL
;
1616 * Free the service path
1619 ExFreePool(ImagePath
.Buffer
);
1622 * Unload the module and release the references to the device object
1625 if (DriverObject
->DriverUnload
)
1626 (*DriverObject
->DriverUnload
)(DriverObject
);
1627 ObDereferenceObject(DriverObject
);
1628 ObDereferenceObject(DriverObject
);
1629 LdrUnloadModule(ModuleObject
);
1631 return STATUS_SUCCESS
;
1635 IopMarkLastReinitializeDriver(VOID
)
1639 KeAcquireSpinLock(&DriverReinitListLock
,
1642 if (IsListEmpty(&DriverReinitListHead
))
1644 DriverReinitTailEntry
= NULL
;
1648 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1651 KeReleaseSpinLock(&DriverReinitListLock
,
1657 IopReinitializeDrivers(VOID
)
1659 PDRIVER_REINIT_ITEM ReinitItem
;
1663 KeAcquireSpinLock(&DriverReinitListLock
,
1666 Entry
= DriverReinitTailEntry
;
1668 KeReleaseSpinLock(&DriverReinitListLock
,
1678 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1679 &DriverReinitListLock
);
1683 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1685 /* Increment reinitialization counter */
1686 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1688 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1689 ReinitItem
->Context
,
1690 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1694 if (Entry
== DriverReinitTailEntry
)
1699 /* PUBLIC FUNCTIONS ***********************************************************/
1708 IN PUNICODE_STRING DriverName
, OPTIONAL
1709 IN PDRIVER_INITIALIZE InitializationFunction
1712 WCHAR NameBuffer
[100];
1714 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1716 OBJECT_ATTRIBUTES ObjectAttributes
;
1718 PDRIVER_OBJECT DriverObject
;
1719 UNICODE_STRING ServiceKeyName
;
1723 /* First, create a unique name for the driver if we don't have one */
1726 /* Create a random name and set up the string*/
1727 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1728 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1729 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1730 LocalDriverName
.Buffer
= NameBuffer
;
1734 /* So we can avoid another code path, use a local var */
1735 LocalDriverName
= *DriverName
;
1738 /* Initialize the Attributes */
1739 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1740 InitializeObjectAttributes(&ObjectAttributes
,
1742 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1746 /* Create the Object */
1747 Status
= ObCreateObject(KernelMode
,
1755 (PVOID
*)&DriverObject
);
1757 /* Return on failure */
1758 if (!NT_SUCCESS(Status
)) return Status
;
1760 /* Set up the Object */
1761 RtlZeroMemory(DriverObject
, ObjectSize
);
1762 DriverObject
->Type
= IO_TYPE_DRIVER
;
1763 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1764 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1765 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1766 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1767 DriverObject
->DriverInit
= InitializationFunction
;
1769 /* Invalidate all Major Functions */
1770 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1772 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1775 /* Set up the Service Key Name */
1776 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1777 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1778 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1779 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1780 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1781 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1783 /* Also store it in the Driver Object. This is a bit of a hack. */
1784 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1786 /* Add the Object and get its handle */
1787 Status
= ObInsertObject(DriverObject
,
1794 /* Return on Failure */
1795 if (!NT_SUCCESS(Status
)) return Status
;
1797 /* Now reference it */
1798 Status
= ObReferenceObjectByHandle(hDriver
,
1802 (PVOID
*)&DriverObject
,
1806 /* Finally, call its init function */
1807 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1809 if (!NT_SUCCESS(Status
)) {
1810 /* If it didn't work, then kill the object */
1811 ObMakeTemporaryObject(DriverObject
);
1812 ObDereferenceObject(DriverObject
);
1815 /* Return the Status */
1825 IN PDRIVER_OBJECT DriverObject
1828 /* Simply derefence the Object */
1829 ObDereferenceObject(DriverObject
);
1836 * Loads a device driver.
1840 * Name of the service to load (registry key).
1850 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1852 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1853 UNICODE_STRING ImagePath
;
1854 UNICODE_STRING ServiceName
;
1855 UNICODE_STRING CapturedDriverServiceName
;
1856 KPROCESSOR_MODE PreviousMode
;
1859 PDEVICE_NODE DeviceNode
;
1860 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1861 PDRIVER_OBJECT DriverObject
;
1866 PreviousMode
= KeGetPreviousMode();
1869 * Check security privileges
1872 /* FIXME: Uncomment when privileges will be correctly implemented. */
1874 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1876 DPRINT("Privilege not held\n");
1877 return STATUS_PRIVILEGE_NOT_HELD
;
1881 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1884 if (!NT_SUCCESS(Status
))
1889 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1891 RtlInitUnicodeString(&ImagePath
, NULL
);
1894 * Get the service name from the registry key name.
1896 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1898 ServiceName
= CapturedDriverServiceName
;
1899 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1900 while (CapturedDriverServiceName
.Buffer
!= cur
)
1904 ServiceName
.Buffer
= cur
+ 1;
1905 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1906 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1907 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1917 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1919 RtlInitUnicodeString(&ImagePath
, NULL
);
1921 QueryTable
[0].Name
= L
"Type";
1922 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1923 QueryTable
[0].EntryContext
= &Type
;
1925 QueryTable
[1].Name
= L
"ImagePath";
1926 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1927 QueryTable
[1].EntryContext
= &ImagePath
;
1929 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1930 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1932 if (!NT_SUCCESS(Status
))
1934 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1935 ExFreePool(ImagePath
.Buffer
);
1936 goto ReleaseCapturedString
;
1940 * Normalize the image path for all later processing.
1943 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1945 if (!NT_SUCCESS(Status
))
1947 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1948 goto ReleaseCapturedString
;
1951 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1952 DPRINT("Type: %lx\n", Type
);
1955 * See, if the driver module isn't already loaded
1958 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1959 if (ModuleObject
!= NULL
)
1961 DPRINT("Image already loaded\n");
1962 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1963 goto ReleaseCapturedString
;
1967 * Create device node
1970 /* Use IopRootDeviceNode for now */
1971 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1973 if (!NT_SUCCESS(Status
))
1975 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1976 goto ReleaseCapturedString
;
1980 * Load the driver module
1983 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1985 if (!NT_SUCCESS(Status
))
1987 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1988 IopFreeDeviceNode(DeviceNode
);
1989 goto ReleaseCapturedString
;
1993 * Set a service name for the device node
1996 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1999 * Initialize the driver module
2002 Status
= IopInitializeDriverModule(
2005 &DeviceNode
->ServiceName
,
2006 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2007 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2010 if (!NT_SUCCESS(Status
))
2012 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
2013 LdrUnloadModule(ModuleObject
);
2014 IopFreeDeviceNode(DeviceNode
);
2015 goto ReleaseCapturedString
;
2018 IopInitializeDevice(DeviceNode
, DriverObject
);
2019 Status
= IopStartDevice(DeviceNode
);
2021 ReleaseCapturedString
:
2022 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2031 * Unloads a legacy device driver.
2035 * Name of the service to unload (registry key).
2045 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2047 return IopUnloadDriver(DriverServiceName
, FALSE
);
2051 * IoRegisterDriverReinitialization
2058 IoRegisterDriverReinitialization(
2059 PDRIVER_OBJECT DriverObject
,
2060 PDRIVER_REINITIALIZE ReinitRoutine
,
2063 PDRIVER_REINIT_ITEM ReinitItem
;
2065 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2066 if (ReinitItem
== NULL
)
2069 ReinitItem
->DriverObject
= DriverObject
;
2070 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2071 ReinitItem
->Context
= Context
;
2073 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2075 ExInterlockedInsertTailList(
2076 &DriverReinitListHead
,
2077 &ReinitItem
->ItemEntry
,
2078 &DriverReinitListLock
);
2086 IoRegisterBootDriverReinitialization(
2087 IN PDRIVER_OBJECT DriverObject
,
2088 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2092 PDRIVER_REINIT_ITEM ReinitItem
;
2094 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2095 if (ReinitItem
== NULL
)
2098 ReinitItem
->DriverObject
= DriverObject
;
2099 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2100 ReinitItem
->Context
= Context
;
2102 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2104 ExInterlockedInsertTailList(
2105 &DriverBootReinitListHead
,
2106 &ReinitItem
->ItemEntry
,
2107 &DriverReinitListLock
);
2111 * IoAllocateDriverObjectExtension
2118 IoAllocateDriverObjectExtension(
2119 PDRIVER_OBJECT DriverObject
,
2120 PVOID ClientIdentificationAddress
,
2121 ULONG DriverObjectExtensionSize
,
2122 PVOID
*DriverObjectExtension
)
2125 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2126 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2128 NewDriverExtension
= ExAllocatePoolWithTag(
2130 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2131 DriverObjectExtensionSize
,
2132 TAG_DRIVER_EXTENSION
);
2134 if (NewDriverExtension
== NULL
)
2136 return STATUS_INSUFFICIENT_RESOURCES
;
2139 OldIrql
= KeRaiseIrqlToDpcLevel();
2141 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2142 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2144 for (DriverExtensions
= DriverObject
->DriverSection
;
2145 DriverExtensions
!= NULL
;
2146 DriverExtensions
= DriverExtensions
->Link
)
2148 if (DriverExtensions
->ClientIdentificationAddress
==
2149 ClientIdentificationAddress
)
2151 KfLowerIrql(OldIrql
);
2152 return STATUS_OBJECT_NAME_COLLISION
;
2156 DriverObject
->DriverSection
= NewDriverExtension
;
2158 KfLowerIrql(OldIrql
);
2160 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2162 return STATUS_SUCCESS
;
2166 * IoGetDriverObjectExtension
2173 IoGetDriverObjectExtension(
2174 PDRIVER_OBJECT DriverObject
,
2175 PVOID ClientIdentificationAddress
)
2178 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2180 OldIrql
= KeRaiseIrqlToDpcLevel();
2182 for (DriverExtensions
= DriverObject
->DriverSection
;
2183 DriverExtensions
!= NULL
&&
2184 DriverExtensions
->ClientIdentificationAddress
!=
2185 ClientIdentificationAddress
;
2186 DriverExtensions
= DriverExtensions
->Link
)
2189 KfLowerIrql(OldIrql
);
2191 if (DriverExtensions
== NULL
)
2194 return &DriverExtensions
->Extension
;