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 RtlFreeUnicodeString(&Object
->DriverName
);
193 OldIrql
= KeRaiseIrqlToDpcLevel();
195 for (DriverExtension
= Object
->DriverSection
;
196 DriverExtension
!= NULL
;
197 DriverExtension
= NextDriverExtension
)
199 NextDriverExtension
= DriverExtension
->Link
;
200 ExFreePool(DriverExtension
);
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 RtlFreeUnicodeString(&InputImagePath
);
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 RtlFreeUnicodeString(&ServiceImagePath
);
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 UNICODE_STRING RegistryKey
;
548 PDRIVER_INITIALIZE DriverEntry
= ModuleObject
->EntryPoint
;
550 WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
552 Status
= IopCreateDriverObject(
558 ModuleObject
->Length
);
560 if (!NT_SUCCESS(Status
))
562 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
566 if (ServiceName
->Buffer
)
568 RegistryKey
.Length
= ServiceName
->Length
+
569 sizeof(ServicesKeyName
) - sizeof(UNICODE_NULL
);
570 RegistryKey
.MaximumLength
= RegistryKey
.Length
+ sizeof(UNICODE_NULL
);
571 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
572 wcscpy(RegistryKey
.Buffer
, ServicesKeyName
);
573 wcscat(RegistryKey
.Buffer
, ServiceName
->Buffer
);
577 RtlInitUnicodeString(&RegistryKey
, NULL
);
580 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
581 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
583 IopMarkLastReinitializeDriver();
585 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
586 if (!NT_SUCCESS(Status
))
588 ObMakeTemporaryObject(*DriverObject
);
589 ObDereferenceObject(*DriverObject
);
593 IopReinitializeDrivers();
595 return STATUS_SUCCESS
;
599 * IopAttachFilterDriversCallback
601 * Internal routine used by IopAttachFilterDrivers.
605 IopAttachFilterDriversCallback(
613 PDEVICE_NODE DeviceNode
= Context
;
614 UNICODE_STRING ServiceName
;
616 PMODULE_OBJECT ModuleObject
;
617 PDRIVER_OBJECT DriverObject
;
620 for (Filters
= ValueData
;
621 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
623 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
625 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
626 ServiceName
.Buffer
= Filters
;
627 ServiceName
.MaximumLength
=
628 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
630 /* Load and initialize the filter driver */
631 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
632 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
634 if (!NT_SUCCESS(Status
))
637 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
638 FALSE
, &DriverObject
);
639 if (!NT_SUCCESS(Status
))
644 /* get existing DriverObject pointer */
645 Status
= IopCreateDriverObject(
651 ModuleObject
->Length
);
652 if (!NT_SUCCESS(Status
))
656 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
657 if (!NT_SUCCESS(Status
))
661 return STATUS_SUCCESS
;
665 * IopAttachFilterDrivers
667 * Load filter drivers for specified device node.
671 * Set to TRUE for loading lower level filters or FALSE for upper
676 IopAttachFilterDrivers(
677 PDEVICE_NODE DeviceNode
,
680 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
682 UNICODE_STRING Class
;
683 WCHAR ClassBuffer
[40];
687 * First load the device filters
690 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
692 QueryTable
[0].Name
= L
"LowerFilters";
694 QueryTable
[0].Name
= L
"UpperFilters";
695 QueryTable
[0].EntryContext
= NULL
;
696 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
697 QueryTable
[1].QueryRoutine
= NULL
;
698 QueryTable
[1].Name
= NULL
;
700 KeyBuffer
= ExAllocatePool(
702 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
703 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
704 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
706 RtlQueryRegistryValues(
707 RTL_REGISTRY_ABSOLUTE
,
714 * Now get the class GUID
718 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
719 Class
.Buffer
= ClassBuffer
;
720 QueryTable
[0].QueryRoutine
= NULL
;
721 QueryTable
[0].Name
= L
"ClassGUID";
722 QueryTable
[0].EntryContext
= &Class
;
723 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
725 Status
= RtlQueryRegistryValues(
726 RTL_REGISTRY_ABSOLUTE
,
732 ExFreePool(KeyBuffer
);
735 * Load the class filter driver
738 if (NT_SUCCESS(Status
))
740 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
742 QueryTable
[0].Name
= L
"LowerFilters";
744 QueryTable
[0].Name
= L
"UpperFilters";
745 QueryTable
[0].EntryContext
= NULL
;
746 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
748 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
749 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
750 wcscat(KeyBuffer
, ClassBuffer
);
752 RtlQueryRegistryValues(
753 RTL_REGISTRY_ABSOLUTE
,
759 ExFreePool(KeyBuffer
);
762 return STATUS_SUCCESS
;
765 static NTSTATUS STDCALL
766 IopGetGroupOrderList(PWSTR ValueName
,
773 PSERVICE_GROUP Group
;
775 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
776 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
778 if (ValueType
== REG_BINARY
&&
780 ValueLength
>= sizeof(DWORD
) &&
781 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
783 Group
= (PSERVICE_GROUP
)Context
;
784 Group
->TagCount
= ((PULONG
)ValueData
)[0];
785 if (Group
->TagCount
> 0)
787 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
789 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
790 if (Group
->TagArray
== NULL
)
793 return STATUS_INSUFFICIENT_RESOURCES
;
795 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
800 return STATUS_UNSUCCESSFUL
;
804 return STATUS_SUCCESS
;
807 static NTSTATUS STDCALL
808 IopCreateGroupListEntry(PWSTR ValueName
,
815 PSERVICE_GROUP Group
;
816 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
820 if (ValueType
== REG_SZ
)
822 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
824 Group
= ExAllocatePool(NonPagedPool
,
825 sizeof(SERVICE_GROUP
));
828 return(STATUS_INSUFFICIENT_RESOURCES
);
831 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
833 if (!RtlpCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
, NonPagedPool
))
836 return(STATUS_INSUFFICIENT_RESOURCES
);
839 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
840 QueryTable
[0].Name
= (PWSTR
)ValueData
;
841 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
843 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
848 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
850 InsertTailList(&GroupListHead
,
851 &Group
->GroupListEntry
);
854 return(STATUS_SUCCESS
);
858 static NTSTATUS STDCALL
859 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
861 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
865 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
867 /* Allocate service entry */
868 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
871 DPRINT1("ExAllocatePool() failed\n");
872 return(STATUS_INSUFFICIENT_RESOURCES
);
874 RtlZeroMemory(Service
, sizeof(SERVICE
));
876 /* Get service data */
877 RtlZeroMemory(&QueryTable
,
880 QueryTable
[0].Name
= L
"Start";
881 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
882 QueryTable
[0].EntryContext
= &Service
->Start
;
884 QueryTable
[1].Name
= L
"Type";
885 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
886 QueryTable
[1].EntryContext
= &Service
->Type
;
888 QueryTable
[2].Name
= L
"ErrorControl";
889 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
890 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
892 QueryTable
[3].Name
= L
"Group";
893 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
894 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
896 QueryTable
[4].Name
= L
"ImagePath";
897 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
898 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
900 QueryTable
[5].Name
= L
"Tag";
901 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
902 QueryTable
[5].EntryContext
= &Service
->Tag
;
904 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
909 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
911 RtlFreeUnicodeString(&Service
->ServiceGroup
);
912 RtlFreeUnicodeString(&Service
->ImagePath
);
917 /* Copy service name */
918 Service
->ServiceName
.Length
= ServiceName
->Length
;
919 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
920 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
921 Service
->ServiceName
.MaximumLength
);
922 RtlCopyMemory(Service
->ServiceName
.Buffer
,
924 ServiceName
->Length
);
925 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
927 /* Build registry path */
928 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
929 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
930 MAX_PATH
* sizeof(WCHAR
));
931 wcscpy(Service
->RegistryPath
.Buffer
,
932 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
933 wcscat(Service
->RegistryPath
.Buffer
,
934 Service
->ServiceName
.Buffer
);
935 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
937 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
938 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
939 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
940 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
941 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
942 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
944 /* Append service entry */
945 InsertTailList(&ServiceListHead
,
946 &Service
->ServiceListEntry
);
948 return(STATUS_SUCCESS
);
952 NTSTATUS INIT_FUNCTION
953 IoCreateDriverList(VOID
)
955 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
956 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
957 OBJECT_ATTRIBUTES ObjectAttributes
;
958 UNICODE_STRING ServicesKeyName
;
959 UNICODE_STRING SubKeyName
;
964 ULONG KeyInfoLength
= 0;
965 ULONG ReturnedLength
;
967 DPRINT("IoCreateDriverList() called\n");
969 /* Initialize basic variables */
970 InitializeListHead(&GroupListHead
);
971 InitializeListHead(&ServiceListHead
);
973 /* Build group order list */
974 RtlZeroMemory(&QueryTable
,
977 QueryTable
[0].Name
= L
"List";
978 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
980 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
981 L
"ServiceGroupOrder",
985 if (!NT_SUCCESS(Status
))
988 /* Enumerate services and create the service list */
989 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
990 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
992 InitializeObjectAttributes(&ObjectAttributes
,
994 OBJ_CASE_INSENSITIVE
,
998 Status
= ZwOpenKey(&KeyHandle
,
999 KEY_ENUMERATE_SUB_KEYS
,
1001 if (!NT_SUCCESS(Status
))
1006 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1007 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1008 if (KeyInfo
== NULL
)
1011 return(STATUS_INSUFFICIENT_RESOURCES
);
1017 Status
= ZwEnumerateKey(KeyHandle
,
1019 KeyBasicInformation
,
1023 if (NT_SUCCESS(Status
))
1025 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1028 SubKeyName
.Length
= KeyInfo
->NameLength
;
1029 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1030 SubKeyName
.Buffer
= KeyInfo
->Name
;
1031 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1033 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1034 IopCreateServiceListEntry(&SubKeyName
);
1038 if (!NT_SUCCESS(Status
))
1044 ExFreePool(KeyInfo
);
1047 DPRINT("IoCreateDriverList() done\n");
1049 return(STATUS_SUCCESS
);
1052 NTSTATUS INIT_FUNCTION
1053 IoDestroyDriverList(VOID
)
1055 PLIST_ENTRY GroupEntry
;
1056 PLIST_ENTRY ServiceEntry
;
1057 PSERVICE_GROUP CurrentGroup
;
1058 PSERVICE CurrentService
;
1060 DPRINT("IoDestroyDriverList() called\n");
1062 /* Destroy group list */
1063 GroupEntry
= GroupListHead
.Flink
;
1064 while (GroupEntry
!= &GroupListHead
)
1066 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1068 RtlFreeUnicodeString(&CurrentGroup
->GroupName
);
1069 RemoveEntryList(GroupEntry
);
1070 if (CurrentGroup
->TagArray
)
1072 ExFreePool(CurrentGroup
->TagArray
);
1074 ExFreePool(CurrentGroup
);
1076 GroupEntry
= GroupListHead
.Flink
;
1079 /* Destroy service list */
1080 ServiceEntry
= ServiceListHead
.Flink
;
1081 while (ServiceEntry
!= &ServiceListHead
)
1083 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1085 RtlFreeUnicodeString(&CurrentService
->ServiceName
);
1086 RtlFreeUnicodeString(&CurrentService
->RegistryPath
);
1087 RtlFreeUnicodeString(&CurrentService
->ServiceGroup
);
1088 RtlFreeUnicodeString(&CurrentService
->ImagePath
);
1089 RemoveEntryList(ServiceEntry
);
1090 ExFreePool(CurrentService
);
1092 ServiceEntry
= ServiceListHead
.Flink
;
1095 DPRINT("IoDestroyDriverList() done\n");
1097 return(STATUS_SUCCESS
);
1100 VOID STATIC INIT_FUNCTION
1101 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1105 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1107 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1112 * IopInitializeBuiltinDriver
1114 * Initialize a driver that is already loaded in memory.
1117 NTSTATUS FASTCALL INIT_FUNCTION
1118 IopInitializeBuiltinDriver(
1119 PDEVICE_NODE ModuleDeviceNode
,
1120 PVOID ModuleLoadBase
,
1124 PMODULE_OBJECT ModuleObject
;
1125 PDEVICE_NODE DeviceNode
;
1126 PDRIVER_OBJECT DriverObject
;
1128 CHAR TextBuffer
[256];
1129 PCHAR FileNameWithoutPath
;
1130 LPWSTR FileExtension
;
1132 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1133 FileName
, ModuleLoadBase
, ModuleLength
);
1136 * Display 'Initializing XXX...' message
1139 sprintf(TextBuffer
, "Initializing %s...\n", FileName
);
1140 HalDisplayString(TextBuffer
);
1143 * Determine the right device object
1146 if (ModuleDeviceNode
== NULL
)
1148 /* Use IopRootDeviceNode for now */
1149 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1150 if (!NT_SUCCESS(Status
))
1152 CPRINT("Driver load failed, status (%x)\n", Status
);
1157 DeviceNode
= ModuleDeviceNode
;
1161 * Generate filename without path (not needed by freeldr)
1164 FileNameWithoutPath
= strrchr(FileName
, '\\');
1165 if (FileNameWithoutPath
== NULL
)
1167 FileNameWithoutPath
= FileName
;
1174 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1175 FileNameWithoutPath
);
1176 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1178 if (!NT_SUCCESS(Status
))
1180 if (ModuleDeviceNode
== NULL
)
1181 IopFreeDeviceNode(DeviceNode
);
1182 CPRINT("Driver load failed, status (%x)\n", Status
);
1187 KDB_SYMBOLFILE_HOOK(FileName
);
1190 * Strip the file extension from ServiceName
1193 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1194 if (FileExtension
!= NULL
)
1196 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1197 FileExtension
[0] = 0;
1201 * Initialize the driver
1204 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1205 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1207 if (!NT_SUCCESS(Status
))
1209 if (ModuleDeviceNode
== NULL
)
1210 IopFreeDeviceNode(DeviceNode
);
1211 CPRINT("Driver load failed, status (%x)\n", Status
);
1215 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1221 * IopInitializeBootDrivers
1223 * Initialize boot drivers and free memory for boot files.
1233 IopInitializeBootDrivers(VOID
)
1235 ULONG BootDriverCount
;
1241 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1243 UNICODE_STRING DriverName
;
1246 DPRINT("IopInitializeBootDrivers()\n");
1248 BootDriverCount
= 0;
1249 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1251 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1252 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1253 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1254 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1255 Extension
= strrchr(ModuleName
, '.');
1256 if (Extension
== NULL
)
1259 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1261 /* Process symbols for *.exe and *.dll */
1262 KDB_SYMBOLFILE_HOOK(ModuleName
);
1264 /* Log *.exe and *.dll files */
1265 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1266 IopBootLog(&DriverName
, TRUE
);
1267 RtlFreeUnicodeString(&DriverName
);
1269 else if (!_stricmp(Extension
, ".sys"))
1271 /* Initialize and log boot start driver */
1274 Status
= IopInitializeBuiltinDriver(NULL
,
1278 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1279 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1280 RtlFreeUnicodeString(&DriverName
);
1287 * Free memory for all boot files, except ntoskrnl.exe.
1289 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1291 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1292 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1295 KeLoaderBlock
.ModsCount
= 0;
1297 if (BootDriverCount
== 0)
1299 DbgPrint("No boot drivers available.\n");
1304 static INIT_FUNCTION NTSTATUS
1305 IopLoadDriver(PSERVICE Service
)
1307 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1309 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
);
1310 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1311 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1312 if (!NT_SUCCESS(Status
))
1314 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status
);
1316 if (Service
->ErrorControl
== 1)
1320 else if (Service
->ErrorControl
== 2)
1322 if (IsLastKnownGood
== FALSE
)
1324 /* Boot last known good configuration */
1327 else if (Service
->ErrorControl
== 3)
1329 if (IsLastKnownGood
== FALSE
)
1331 /* Boot last known good configuration */
1345 * IopInitializeSystemDrivers
1347 * Load drivers marked as system start.
1357 IopInitializeSystemDrivers(VOID
)
1359 PLIST_ENTRY GroupEntry
;
1360 PLIST_ENTRY ServiceEntry
;
1361 PSERVICE_GROUP CurrentGroup
;
1362 PSERVICE CurrentService
;
1366 DPRINT("IopInitializeSystemDrivers()\n");
1368 GroupEntry
= GroupListHead
.Flink
;
1369 while (GroupEntry
!= &GroupListHead
)
1371 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1373 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1375 /* Load all drivers with a valid tag */
1376 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1378 ServiceEntry
= ServiceListHead
.Flink
;
1379 while (ServiceEntry
!= &ServiceListHead
)
1381 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1383 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1384 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1385 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1386 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1388 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1389 Status
= IopLoadDriver(CurrentService
);
1391 ServiceEntry
= ServiceEntry
->Flink
;
1395 /* Load all drivers without a tag or with an invalid tag */
1396 ServiceEntry
= ServiceListHead
.Flink
;
1397 while (ServiceEntry
!= &ServiceListHead
)
1399 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1400 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1401 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1402 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1404 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1406 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1411 if (i
>= CurrentGroup
->TagCount
)
1413 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1414 Status
= IopLoadDriver(CurrentService
);
1417 ServiceEntry
= ServiceEntry
->Flink
;
1420 GroupEntry
= GroupEntry
->Flink
;
1423 DPRINT("IopInitializeSystemDrivers() done\n");
1429 * Unloads a device driver.
1433 * Name of the service to unload (registry key).
1436 * Whether to unload Plug & Plug or only legacy drivers. If this
1437 * parameter is set to FALSE, the routine will unload only legacy
1444 * Guard the whole function by SEH.
1448 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1450 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1451 UNICODE_STRING ImagePath
;
1452 UNICODE_STRING ServiceName
;
1453 UNICODE_STRING ObjectName
;
1454 PDRIVER_OBJECT DriverObject
;
1455 PMODULE_OBJECT ModuleObject
;
1459 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1462 * Get the service name from the registry key name
1465 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1467 Start
= DriverServiceName
->Buffer
;
1471 RtlInitUnicodeString(&ServiceName
, Start
);
1474 * Construct the driver object name
1477 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1478 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1479 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1480 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1481 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1482 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1485 * Find the driver object
1488 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1489 KernelMode
, 0, (PVOID
*)&DriverObject
);
1491 if (!NT_SUCCESS(Status
))
1493 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1498 * Free the buffer for driver object name
1501 ExFreePool(ObjectName
.Buffer
);
1504 * Get path of service...
1507 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1509 RtlInitUnicodeString(&ImagePath
, NULL
);
1511 QueryTable
[0].Name
= L
"ImagePath";
1512 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1513 QueryTable
[0].EntryContext
= &ImagePath
;
1515 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1516 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1518 if (!NT_SUCCESS(Status
))
1520 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1525 * Normalize the image path for all later processing.
1528 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1530 if (!NT_SUCCESS(Status
))
1532 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1537 * ... and check if it's loaded
1540 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1541 if (ModuleObject
== NULL
)
1543 return STATUS_UNSUCCESSFUL
;
1547 * Free the service path
1550 RtlFreeUnicodeString(&ImagePath
);
1553 * Unload the module and release the references to the device object
1556 if (DriverObject
->DriverUnload
)
1557 (*DriverObject
->DriverUnload
)(DriverObject
);
1558 ObDereferenceObject(DriverObject
);
1559 ObDereferenceObject(DriverObject
);
1560 LdrUnloadModule(ModuleObject
);
1562 return STATUS_SUCCESS
;
1566 IopMarkLastReinitializeDriver(VOID
)
1570 KeAcquireSpinLock(&DriverReinitListLock
,
1573 if (IsListEmpty(&DriverReinitListHead
))
1575 DriverReinitTailEntry
= NULL
;
1579 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1582 KeReleaseSpinLock(&DriverReinitListLock
,
1588 IopReinitializeDrivers(VOID
)
1590 PDRIVER_REINIT_ITEM ReinitItem
;
1594 KeAcquireSpinLock(&DriverReinitListLock
,
1597 if (DriverReinitTailEntry
== NULL
)
1599 KeReleaseSpinLock(&DriverReinitListLock
,
1604 KeReleaseSpinLock(&DriverReinitListLock
,
1609 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1610 &DriverReinitListLock
);
1614 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1616 /* Increment reinitialization counter */
1617 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1619 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1620 ReinitItem
->Context
,
1621 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1625 if (Entry
== DriverReinitTailEntry
)
1630 /* PUBLIC FUNCTIONS ***********************************************************/
1639 IN PUNICODE_STRING DriverName
, OPTIONAL
1640 IN PDRIVER_INITIALIZE InitializationFunction
1643 WCHAR NameBuffer
[100];
1645 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1647 OBJECT_ATTRIBUTES ObjectAttributes
;
1649 PDRIVER_OBJECT DriverObject
;
1650 UNICODE_STRING ServiceKeyName
;
1654 /* First, create a unique name for the driver if we don't have one */
1657 /* Create a random name and set up the string*/
1658 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1659 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1660 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1661 LocalDriverName
.Buffer
= NameBuffer
;
1665 /* So we can avoid another code path, use a local var */
1666 LocalDriverName
= *DriverName
;
1669 /* Initialize the Attributes */
1670 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1671 InitializeObjectAttributes(&ObjectAttributes
,
1673 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1677 /* Create the Object */
1678 Status
= ObCreateObject(KernelMode
,
1686 (PVOID
*)&DriverObject
);
1688 /* Return on failure */
1689 if (!NT_SUCCESS(Status
)) return Status
;
1691 /* Set up the Object */
1692 RtlZeroMemory(DriverObject
, ObjectSize
);
1693 DriverObject
->Type
= IO_TYPE_DRIVER
;
1694 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1695 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1696 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1697 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1698 DriverObject
->DriverInit
= InitializationFunction
;
1700 /* Invalidate all Major Functions */
1701 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1703 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1706 /* Set up the Service Key Name */
1707 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1708 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1709 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1710 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1711 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1712 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1714 /* Also store it in the Driver Object. This is a bit of a hack. */
1715 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1717 /* Add the Object and get its handle */
1718 Status
= ObInsertObject(DriverObject
,
1725 /* Return on Failure */
1726 if (!NT_SUCCESS(Status
)) return Status
;
1728 /* Now reference it */
1729 Status
= ObReferenceObjectByHandle(hDriver
,
1733 (PVOID
*)&DriverObject
,
1737 /* Finally, call its init function */
1738 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1740 if (!NT_SUCCESS(Status
)) {
1741 /* If it didn't work, then kill the object */
1742 ObMakeTemporaryObject(DriverObject
);
1743 ObDereferenceObject(DriverObject
);
1746 /* Return the Status */
1756 IN PDRIVER_OBJECT DriverObject
1759 /* Simply derefence the Object */
1760 ObDereferenceObject(DriverObject
);
1767 * Loads a device driver.
1771 * Name of the service to load (registry key).
1781 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1783 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1784 UNICODE_STRING ImagePath
;
1785 UNICODE_STRING ServiceName
;
1788 PDEVICE_NODE DeviceNode
;
1789 PMODULE_OBJECT ModuleObject
;
1790 PDRIVER_OBJECT DriverObject
;
1793 DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName
);
1796 * Check security privileges
1799 /* FIXME: Uncomment when privileges will be correctly implemented. */
1801 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, KeGetPreviousMode()))
1803 DPRINT("Privilege not held\n");
1804 return STATUS_PRIVILEGE_NOT_HELD
;
1808 RtlInitUnicodeString(&ImagePath
, NULL
);
1811 * Get the service name from the registry key name.
1814 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1816 Start
= DriverServiceName
->Buffer
;
1820 RtlInitUnicodeString(&ServiceName
, Start
);
1826 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1828 RtlInitUnicodeString(&ImagePath
, NULL
);
1830 QueryTable
[0].Name
= L
"Type";
1831 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1832 QueryTable
[0].EntryContext
= &Type
;
1834 QueryTable
[1].Name
= L
"ImagePath";
1835 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1836 QueryTable
[1].EntryContext
= &ImagePath
;
1838 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1839 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1841 if (!NT_SUCCESS(Status
))
1843 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1844 RtlFreeUnicodeString(&ImagePath
);
1849 * Normalize the image path for all later processing.
1852 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1854 if (!NT_SUCCESS(Status
))
1856 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1860 DPRINT("FullImagePath: '%S'\n", ImagePath
.Buffer
);
1861 DPRINT("Type: %lx\n", Type
);
1864 * See, if the driver module isn't already loaded
1867 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1868 if (ModuleObject
!= NULL
)
1870 DPRINT("Image already loaded\n");
1871 return STATUS_IMAGE_ALREADY_LOADED
;
1875 * Create device node
1878 /* Use IopRootDeviceNode for now */
1879 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1881 if (!NT_SUCCESS(Status
))
1883 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1888 * Load the driver module
1891 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1893 if (!NT_SUCCESS(Status
))
1895 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1896 IopFreeDeviceNode(DeviceNode
);
1901 * Set a service name for the device node
1904 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1906 Start
= DriverServiceName
->Buffer
;
1909 RtlpCreateUnicodeString(&DeviceNode
->ServiceName
, Start
, NonPagedPool
);
1912 * Initialize the driver module
1915 Status
= IopInitializeDriverModule(
1918 &DeviceNode
->ServiceName
,
1919 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1920 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1923 if (!NT_SUCCESS(Status
))
1925 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1926 LdrUnloadModule(ModuleObject
);
1927 IopFreeDeviceNode(DeviceNode
);
1931 IopInitializeDevice(DeviceNode
, DriverObject
);
1939 * Unloads a legacy device driver.
1943 * Name of the service to unload (registry key).
1953 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1955 return IopUnloadDriver(DriverServiceName
, FALSE
);
1959 * IoRegisterDriverReinitialization
1966 IoRegisterDriverReinitialization(
1967 PDRIVER_OBJECT DriverObject
,
1968 PDRIVER_REINITIALIZE ReinitRoutine
,
1971 PDRIVER_REINIT_ITEM ReinitItem
;
1973 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
1974 if (ReinitItem
== NULL
)
1977 ReinitItem
->DriverObject
= DriverObject
;
1978 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1979 ReinitItem
->Context
= Context
;
1981 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1983 ExInterlockedInsertTailList(
1984 &DriverReinitListHead
,
1985 &ReinitItem
->ItemEntry
,
1986 &DriverReinitListLock
);
1994 IoRegisterBootDriverReinitialization(
1995 IN PDRIVER_OBJECT DriverObject
,
1996 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2000 PDRIVER_REINIT_ITEM ReinitItem
;
2002 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2003 if (ReinitItem
== NULL
)
2006 ReinitItem
->DriverObject
= DriverObject
;
2007 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2008 ReinitItem
->Context
= Context
;
2010 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2012 ExInterlockedInsertTailList(
2013 &DriverBootReinitListHead
,
2014 &ReinitItem
->ItemEntry
,
2015 &DriverReinitListLock
);
2019 * IoAllocateDriverObjectExtension
2026 IoAllocateDriverObjectExtension(
2027 PDRIVER_OBJECT DriverObject
,
2028 PVOID ClientIdentificationAddress
,
2029 ULONG DriverObjectExtensionSize
,
2030 PVOID
*DriverObjectExtension
)
2033 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2034 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2036 NewDriverExtension
= ExAllocatePoolWithTag(
2038 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2039 DriverObjectExtensionSize
,
2040 TAG_DRIVER_EXTENSION
);
2042 if (NewDriverExtension
== NULL
)
2044 return STATUS_INSUFFICIENT_RESOURCES
;
2047 OldIrql
= KeRaiseIrqlToDpcLevel();
2049 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2050 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2052 for (DriverExtensions
= DriverObject
->DriverSection
;
2053 DriverExtensions
!= NULL
;
2054 DriverExtensions
= DriverExtensions
->Link
)
2056 if (DriverExtensions
->ClientIdentificationAddress
==
2057 ClientIdentificationAddress
)
2059 KfLowerIrql(OldIrql
);
2060 return STATUS_OBJECT_NAME_COLLISION
;
2064 DriverObject
->DriverSection
= NewDriverExtension
;
2066 KfLowerIrql(OldIrql
);
2068 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2070 return STATUS_SUCCESS
;
2074 * IoGetDriverObjectExtension
2081 IoGetDriverObjectExtension(
2082 PDRIVER_OBJECT DriverObject
,
2083 PVOID ClientIdentificationAddress
)
2086 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2088 OldIrql
= KeRaiseIrqlToDpcLevel();
2090 for (DriverExtensions
= DriverObject
->DriverSection
;
2091 DriverExtensions
!= NULL
&&
2092 DriverExtensions
->ClientIdentificationAddress
!=
2093 ClientIdentificationAddress
;
2094 DriverExtensions
= DriverExtensions
->Link
)
2097 KfLowerIrql(OldIrql
);
2099 if (DriverExtensions
== NULL
)
2102 return &DriverExtensions
->Extension
;