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 ***************************************************************/
84 IopDeleteDriver(PVOID ObjectBody
);
86 /* PRIVATE FUNCTIONS **********************************************************/
89 IopInitDriverImplementation(VOID
)
91 /* Register the process object type */
92 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
93 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'R');
94 IoDriverObjectType
->TotalObjects
= 0;
95 IoDriverObjectType
->TotalHandles
= 0;
96 IoDriverObjectType
->PeakObjects
= 0;
97 IoDriverObjectType
->PeakHandles
= 0;
98 IoDriverObjectType
->PagedPoolCharge
= 0;
99 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(DRIVER_OBJECT
);
100 IoDriverObjectType
->Dump
= NULL
;
101 IoDriverObjectType
->Open
= NULL
;
102 IoDriverObjectType
->Close
= NULL
;
103 IoDriverObjectType
->Delete
= IopDeleteDriver
;
104 IoDriverObjectType
->Parse
= NULL
;
105 IoDriverObjectType
->Security
= NULL
;
106 IoDriverObjectType
->QueryName
= NULL
;
107 IoDriverObjectType
->OkayToClose
= NULL
;
108 RtlInitUnicodeString(&IoDriverObjectType
->TypeName
, L
"Driver");
110 ObpCreateTypeObject(IoDriverObjectType
);
112 InitializeListHead(&DriverReinitListHead
);
113 KeInitializeSpinLock(&DriverReinitListLock
);
114 DriverReinitTailEntry
= NULL
;
116 InitializeListHead(&DriverBootReinitListHead
);
117 KeInitializeSpinLock(&DriverBootReinitListLock
);
118 DriverBootReinitTailEntry
= NULL
;
122 IopInvalidDeviceRequest(
123 PDEVICE_OBJECT DeviceObject
,
126 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
127 Irp
->IoStatus
.Information
= 0;
128 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
129 return STATUS_INVALID_DEVICE_REQUEST
;
133 IopDeleteDriver(PVOID ObjectBody
)
135 PDRIVER_OBJECT Object
= ObjectBody
;
137 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
139 DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody
);
141 ExFreePool(Object
->DriverExtension
);
142 ExFreePool(Object
->DriverName
.Buffer
);
144 OldIrql
= KeRaiseIrqlToDpcLevel();
146 for (DriverExtension
= Object
->DriverSection
;
147 DriverExtension
!= NULL
;
148 DriverExtension
= NextDriverExtension
)
150 NextDriverExtension
= DriverExtension
->Link
;
151 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
154 KfLowerIrql(OldIrql
);
158 IopCreateDriverObject(
159 PDRIVER_OBJECT
*DriverObject
,
160 PUNICODE_STRING ServiceName
,
161 ULONG CreateAttributes
,
163 PVOID DriverImageStart
,
164 ULONG DriverImageSize
)
166 PDRIVER_OBJECT Object
;
167 WCHAR NameBuffer
[MAX_PATH
];
168 UNICODE_STRING DriverName
;
169 OBJECT_ATTRIBUTES ObjectAttributes
;
174 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
175 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
177 *DriverObject
= NULL
;
179 /* Create ModuleName string */
180 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
182 if (FileSystem
== TRUE
)
183 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
185 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
186 wcscat(NameBuffer
, ServiceName
->Buffer
);
188 RtlInitUnicodeString(&DriverName
, NameBuffer
);
189 DPRINT("Driver name: '%wZ'\n", &DriverName
);
191 Buffer
= (PWSTR
)ExAllocatePool(NonPagedPool
, DriverName
.Length
);
192 /* If we don't success, it is not a problem. Our driver
193 * object will not have associated driver name... */
197 RtlInitUnicodeString(&DriverName
, NULL
);
200 /* Initialize ObjectAttributes for driver object */
201 InitializeObjectAttributes(
204 CreateAttributes
| OBJ_PERMANENT
,
208 /* Create driver object */
209 Status
= ObCreateObject(
215 sizeof(DRIVER_OBJECT
),
220 if (!NT_SUCCESS(Status
))
225 /* Create driver extension */
226 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
227 ExAllocatePoolWithTag(
229 sizeof(DRIVER_EXTENSION
),
230 TAG_DRIVER_EXTENSION
);
232 if (Object
->DriverExtension
== NULL
)
234 return STATUS_NO_MEMORY
;
237 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
239 Object
->Type
= IO_TYPE_DRIVER
;
241 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
242 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
244 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
246 Object
->DriverStart
= DriverImageStart
;
247 Object
->DriverSize
= DriverImageSize
;
250 if (!Object
->DriverName
.Buffer
)
252 Object
->DriverName
.Buffer
= Buffer
;
253 Object
->DriverName
.Length
= Object
->DriverName
.MaximumLength
= DriverName
.Length
;
254 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
260 *DriverObject
= Object
;
262 return STATUS_SUCCESS
;
266 * IopDisplayLoadingMessage
268 * Display 'Loading XXX...' message.
272 IopDisplayLoadingMessage(PWCHAR ServiceName
)
274 CHAR TextBuffer
[256];
275 sprintf(TextBuffer
, "Loading %S...\n", ServiceName
);
276 HalDisplayString(TextBuffer
);
280 * IopNormalizeImagePath
282 * Normalize an image path to contain complete path.
286 * The input path and on exit the result path. ImagePath.Buffer
287 * must be allocated by ExAllocatePool on input. Caller is responsible
288 * for freeing the buffer when it's no longer needed.
291 * Name of the service that ImagePath belongs to.
297 * The input image path isn't freed on error.
301 IopNormalizeImagePath(
302 IN OUT PUNICODE_STRING ImagePath
,
303 IN PUNICODE_STRING ServiceName
)
305 UNICODE_STRING InputImagePath
;
310 sizeof(UNICODE_STRING
));
312 if (InputImagePath
.Length
== 0)
314 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
315 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
316 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
317 if (ImagePath
->Buffer
== NULL
)
318 return STATUS_NO_MEMORY
;
320 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
321 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
322 wcscat(ImagePath
->Buffer
, L
".sys");
324 if (InputImagePath
.Buffer
[0] != L
'\\')
326 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
327 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
328 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
329 if (ImagePath
->Buffer
== NULL
)
330 return STATUS_NO_MEMORY
;
332 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
333 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
334 ExFreePool(InputImagePath
.Buffer
);
337 return STATUS_SUCCESS
;
341 * IopLoadServiceModule
343 * Load a module specified by registry settings for service.
347 * Name of the service to load.
354 IopLoadServiceModule(
355 IN PUNICODE_STRING ServiceName
,
356 OUT PMODULE_OBJECT
*ModuleObject
)
358 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
360 UNICODE_STRING ServiceImagePath
;
363 DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName
, ModuleObject
);
366 * Get information about the service.
369 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
371 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
373 QueryTable
[0].Name
= L
"Start";
374 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
375 QueryTable
[0].EntryContext
= &ServiceStart
;
377 QueryTable
[1].Name
= L
"ImagePath";
378 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
379 QueryTable
[1].EntryContext
= &ServiceImagePath
;
381 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
382 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
384 if (!NT_SUCCESS(Status
))
386 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
390 IopDisplayLoadingMessage(ServiceName
->Buffer
);
393 * Normalize the image path for all later processing.
396 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
398 if (!NT_SUCCESS(Status
))
400 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
408 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
410 if (*ModuleObject
== NULL
)
412 Status
= STATUS_UNSUCCESSFUL
;
415 * Special case for boot modules that were loaded by boot loader.
418 if (ServiceStart
== 0)
421 CHAR SearchName
[256];
423 PLOADER_MODULE KeLoaderModules
=
424 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
428 * Improve this searching algorithm by using the image name
429 * stored in registry entry ImageName and use the whole path
430 * (requires change in FreeLoader).
433 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
434 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
436 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
437 if (!_stricmp(ModuleName
, SearchName
))
439 DPRINT("Initializing boot module\n");
441 /* Tell, that the module is already loaded */
442 KeLoaderModules
[i
].Reserved
= 1;
444 Status
= LdrProcessModule(
445 (PVOID
)KeLoaderModules
[i
].ModStart
,
449 KDB_SYMBOLFILE_HOOK(SearchName
);
457 * Case for rest of the drivers (except disabled)
460 else if (ServiceStart
< 4)
462 DPRINT("Loading module\n");
463 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
468 DPRINT("Module already loaded\n");
469 Status
= STATUS_IMAGE_ALREADY_LOADED
;
472 ExFreePool(ServiceImagePath
.Buffer
);
475 * Now check if the module was loaded successfully.
478 if (!NT_SUCCESS(Status
))
480 DPRINT("Module loading failed (Status %x)\n", Status
);
483 DPRINT("Module loading (Status %x)\n", Status
);
489 * IopInitializeDriverModule
491 * Initalize a loaded driver.
495 * Pointer to device node.
498 * Module object representing the driver. It can be retrieve by
499 * IopLoadServiceModule.
502 * Name of the service (as in registry).
505 * Set to TRUE for file system drivers.
508 * On successful return this contains the driver object representing
513 IopInitializeDriverModule(
514 IN PDEVICE_NODE DeviceNode
,
515 IN PMODULE_OBJECT ModuleObject
,
516 IN PUNICODE_STRING ServiceName
,
517 IN BOOLEAN FileSystemDriver
,
518 OUT PDRIVER_OBJECT
*DriverObject
)
520 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
521 UNICODE_STRING RegistryKey
;
522 PDRIVER_INITIALIZE DriverEntry
;
525 DriverEntry
= ModuleObject
->EntryPoint
;
527 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
529 RegistryKey
.Length
= 0;
530 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
531 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
532 if (RegistryKey
.Buffer
== NULL
)
534 return STATUS_INSUFFICIENT_RESOURCES
;
536 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
537 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
541 RtlInitUnicodeString(&RegistryKey
, NULL
);
544 Status
= IopCreateDriverObject(
550 ModuleObject
->Length
);
552 if (!NT_SUCCESS(Status
))
554 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
558 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
559 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
561 IopMarkLastReinitializeDriver();
563 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
565 RtlFreeUnicodeString(&RegistryKey
);
567 if (!NT_SUCCESS(Status
))
569 ObMakeTemporaryObject(*DriverObject
);
570 ObDereferenceObject(*DriverObject
);
574 IopReinitializeDrivers();
576 return STATUS_SUCCESS
;
580 * IopAttachFilterDriversCallback
582 * Internal routine used by IopAttachFilterDrivers.
586 IopAttachFilterDriversCallback(
594 PDEVICE_NODE DeviceNode
= Context
;
595 UNICODE_STRING ServiceName
;
597 PMODULE_OBJECT ModuleObject
;
598 PDRIVER_OBJECT DriverObject
;
601 for (Filters
= ValueData
;
602 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
604 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
606 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
607 ServiceName
.Buffer
= Filters
;
608 ServiceName
.MaximumLength
=
609 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
611 /* Load and initialize the filter driver */
612 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
613 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
615 if (!NT_SUCCESS(Status
))
618 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
619 FALSE
, &DriverObject
);
620 if (!NT_SUCCESS(Status
))
625 /* get existing DriverObject pointer */
626 Status
= IopCreateDriverObject(
632 ModuleObject
->Length
);
633 if (!NT_SUCCESS(Status
))
637 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
638 if (!NT_SUCCESS(Status
))
642 return STATUS_SUCCESS
;
646 * IopAttachFilterDrivers
648 * Load filter drivers for specified device node.
652 * Set to TRUE for loading lower level filters or FALSE for upper
657 IopAttachFilterDrivers(
658 PDEVICE_NODE DeviceNode
,
661 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
663 UNICODE_STRING Class
;
664 WCHAR ClassBuffer
[40];
668 * First load the device filters
671 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
673 QueryTable
[0].Name
= L
"LowerFilters";
675 QueryTable
[0].Name
= L
"UpperFilters";
676 QueryTable
[0].EntryContext
= NULL
;
677 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
678 QueryTable
[1].QueryRoutine
= NULL
;
679 QueryTable
[1].Name
= NULL
;
681 KeyBuffer
= ExAllocatePool(
683 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
684 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
685 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
687 RtlQueryRegistryValues(
688 RTL_REGISTRY_ABSOLUTE
,
695 * Now get the class GUID
699 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
700 Class
.Buffer
= ClassBuffer
;
701 QueryTable
[0].QueryRoutine
= NULL
;
702 QueryTable
[0].Name
= L
"ClassGUID";
703 QueryTable
[0].EntryContext
= &Class
;
704 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
706 Status
= RtlQueryRegistryValues(
707 RTL_REGISTRY_ABSOLUTE
,
713 ExFreePool(KeyBuffer
);
716 * Load the class filter driver
719 if (NT_SUCCESS(Status
))
721 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
723 QueryTable
[0].Name
= L
"LowerFilters";
725 QueryTable
[0].Name
= L
"UpperFilters";
726 QueryTable
[0].EntryContext
= NULL
;
727 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
729 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
730 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
731 wcscat(KeyBuffer
, ClassBuffer
);
733 RtlQueryRegistryValues(
734 RTL_REGISTRY_ABSOLUTE
,
740 ExFreePool(KeyBuffer
);
743 return STATUS_SUCCESS
;
746 static NTSTATUS STDCALL
747 IopGetGroupOrderList(PWSTR ValueName
,
754 PSERVICE_GROUP Group
;
756 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
757 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
759 if (ValueType
== REG_BINARY
&&
761 ValueLength
>= sizeof(DWORD
) &&
762 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
764 Group
= (PSERVICE_GROUP
)Context
;
765 Group
->TagCount
= ((PULONG
)ValueData
)[0];
766 if (Group
->TagCount
> 0)
768 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
770 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
771 if (Group
->TagArray
== NULL
)
774 return STATUS_INSUFFICIENT_RESOURCES
;
776 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
781 return STATUS_UNSUCCESSFUL
;
785 return STATUS_SUCCESS
;
788 static NTSTATUS STDCALL
789 IopCreateGroupListEntry(PWSTR ValueName
,
796 PSERVICE_GROUP Group
;
797 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
801 if (ValueType
== REG_SZ
)
803 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
805 Group
= ExAllocatePool(NonPagedPool
,
806 sizeof(SERVICE_GROUP
));
809 return(STATUS_INSUFFICIENT_RESOURCES
);
812 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
814 if (!RtlpCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
, NonPagedPool
))
817 return(STATUS_INSUFFICIENT_RESOURCES
);
820 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
821 QueryTable
[0].Name
= (PWSTR
)ValueData
;
822 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
824 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
829 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
831 InsertTailList(&GroupListHead
,
832 &Group
->GroupListEntry
);
835 return(STATUS_SUCCESS
);
839 static NTSTATUS STDCALL
840 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
842 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
846 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
848 /* Allocate service entry */
849 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
852 DPRINT1("ExAllocatePool() failed\n");
853 return(STATUS_INSUFFICIENT_RESOURCES
);
855 RtlZeroMemory(Service
, sizeof(SERVICE
));
857 /* Get service data */
858 RtlZeroMemory(&QueryTable
,
861 QueryTable
[0].Name
= L
"Start";
862 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
863 QueryTable
[0].EntryContext
= &Service
->Start
;
865 QueryTable
[1].Name
= L
"Type";
866 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
867 QueryTable
[1].EntryContext
= &Service
->Type
;
869 QueryTable
[2].Name
= L
"ErrorControl";
870 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
871 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
873 QueryTable
[3].Name
= L
"Group";
874 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
875 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
877 QueryTable
[4].Name
= L
"ImagePath";
878 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
879 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
881 QueryTable
[5].Name
= L
"Tag";
882 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
883 QueryTable
[5].EntryContext
= &Service
->Tag
;
885 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
890 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
893 * If something goes wrong during RtlQueryRegistryValues
894 * it'll just drop everything on the floor and return,
895 * so you have to check if the buffers were filled.
896 * Luckily we zerofilled the Service.
898 if (Service
->ServiceGroup
.Buffer
)
900 ExFreePool(Service
->ServiceGroup
.Buffer
);
902 if (Service
->ImagePath
.Buffer
)
904 ExFreePool(Service
->ImagePath
.Buffer
);
910 /* Copy service name */
911 Service
->ServiceName
.Length
= ServiceName
->Length
;
912 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
913 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
914 Service
->ServiceName
.MaximumLength
);
915 RtlCopyMemory(Service
->ServiceName
.Buffer
,
917 ServiceName
->Length
);
918 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
920 /* Build registry path */
921 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
922 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
923 MAX_PATH
* sizeof(WCHAR
));
924 wcscpy(Service
->RegistryPath
.Buffer
,
925 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
926 wcscat(Service
->RegistryPath
.Buffer
,
927 Service
->ServiceName
.Buffer
);
928 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
930 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
931 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
932 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
933 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
934 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
935 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
937 /* Append service entry */
938 InsertTailList(&ServiceListHead
,
939 &Service
->ServiceListEntry
);
941 return(STATUS_SUCCESS
);
945 NTSTATUS INIT_FUNCTION
946 IoCreateDriverList(VOID
)
948 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
949 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
950 OBJECT_ATTRIBUTES ObjectAttributes
;
951 UNICODE_STRING ServicesKeyName
;
952 UNICODE_STRING SubKeyName
;
957 ULONG KeyInfoLength
= 0;
958 ULONG ReturnedLength
;
960 DPRINT("IoCreateDriverList() called\n");
962 /* Initialize basic variables */
963 InitializeListHead(&GroupListHead
);
964 InitializeListHead(&ServiceListHead
);
966 /* Build group order list */
967 RtlZeroMemory(&QueryTable
,
970 QueryTable
[0].Name
= L
"List";
971 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
973 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
974 L
"ServiceGroupOrder",
978 if (!NT_SUCCESS(Status
))
981 /* Enumerate services and create the service list */
982 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
983 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
985 InitializeObjectAttributes(&ObjectAttributes
,
987 OBJ_CASE_INSENSITIVE
,
991 Status
= ZwOpenKey(&KeyHandle
,
992 KEY_ENUMERATE_SUB_KEYS
,
994 if (!NT_SUCCESS(Status
))
999 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1000 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1001 if (KeyInfo
== NULL
)
1004 return(STATUS_INSUFFICIENT_RESOURCES
);
1010 Status
= ZwEnumerateKey(KeyHandle
,
1012 KeyBasicInformation
,
1016 if (NT_SUCCESS(Status
))
1018 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1021 SubKeyName
.Length
= KeyInfo
->NameLength
;
1022 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1023 SubKeyName
.Buffer
= KeyInfo
->Name
;
1024 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1026 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1027 IopCreateServiceListEntry(&SubKeyName
);
1031 if (!NT_SUCCESS(Status
))
1037 ExFreePool(KeyInfo
);
1040 DPRINT("IoCreateDriverList() done\n");
1042 return(STATUS_SUCCESS
);
1045 NTSTATUS INIT_FUNCTION
1046 IoDestroyDriverList(VOID
)
1048 PLIST_ENTRY GroupEntry
;
1049 PLIST_ENTRY ServiceEntry
;
1050 PSERVICE_GROUP CurrentGroup
;
1051 PSERVICE CurrentService
;
1053 DPRINT("IoDestroyDriverList() called\n");
1055 /* Destroy group list */
1056 GroupEntry
= GroupListHead
.Flink
;
1057 while (GroupEntry
!= &GroupListHead
)
1059 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1061 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1062 RemoveEntryList(GroupEntry
);
1063 if (CurrentGroup
->TagArray
)
1065 ExFreePool(CurrentGroup
->TagArray
);
1067 ExFreePool(CurrentGroup
);
1069 GroupEntry
= GroupListHead
.Flink
;
1072 /* Destroy service list */
1073 ServiceEntry
= ServiceListHead
.Flink
;
1074 while (ServiceEntry
!= &ServiceListHead
)
1076 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1078 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1079 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1080 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1081 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1082 RemoveEntryList(ServiceEntry
);
1083 ExFreePool(CurrentService
);
1085 ServiceEntry
= ServiceListHead
.Flink
;
1088 DPRINT("IoDestroyDriverList() done\n");
1090 return(STATUS_SUCCESS
);
1093 VOID STATIC INIT_FUNCTION
1094 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1098 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1100 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1105 * IopInitializeBuiltinDriver
1107 * Initialize a driver that is already loaded in memory.
1110 NTSTATUS FASTCALL INIT_FUNCTION
1111 IopInitializeBuiltinDriver(
1112 PDEVICE_NODE ModuleDeviceNode
,
1113 PVOID ModuleLoadBase
,
1117 PMODULE_OBJECT ModuleObject
;
1118 PDEVICE_NODE DeviceNode
;
1119 PDRIVER_OBJECT DriverObject
;
1121 CHAR TextBuffer
[256];
1122 PCHAR FileNameWithoutPath
;
1123 LPWSTR FileExtension
;
1125 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1126 FileName
, ModuleLoadBase
, ModuleLength
);
1129 * Display 'Initializing XXX...' message
1132 sprintf(TextBuffer
, "Initializing %s...\n", FileName
);
1133 HalDisplayString(TextBuffer
);
1136 * Determine the right device object
1139 if (ModuleDeviceNode
== NULL
)
1141 /* Use IopRootDeviceNode for now */
1142 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1143 if (!NT_SUCCESS(Status
))
1145 CPRINT("Driver load failed, status (%x)\n", Status
);
1150 DeviceNode
= ModuleDeviceNode
;
1154 * Generate filename without path (not needed by freeldr)
1157 FileNameWithoutPath
= strrchr(FileName
, '\\');
1158 if (FileNameWithoutPath
== NULL
)
1160 FileNameWithoutPath
= FileName
;
1167 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1168 FileNameWithoutPath
);
1169 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1171 if (!NT_SUCCESS(Status
))
1173 if (ModuleDeviceNode
== NULL
)
1174 IopFreeDeviceNode(DeviceNode
);
1175 CPRINT("Driver load failed, status (%x)\n", Status
);
1180 KDB_SYMBOLFILE_HOOK(FileName
);
1183 * Strip the file extension from ServiceName
1186 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1187 if (FileExtension
!= NULL
)
1189 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1190 FileExtension
[0] = 0;
1194 * Initialize the driver
1197 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1198 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1200 if (!NT_SUCCESS(Status
))
1202 if (ModuleDeviceNode
== NULL
)
1203 IopFreeDeviceNode(DeviceNode
);
1204 CPRINT("Driver load failed, status (%x)\n", Status
);
1208 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1214 * IopInitializeBootDrivers
1216 * Initialize boot drivers and free memory for boot files.
1226 IopInitializeBootDrivers(VOID
)
1228 ULONG BootDriverCount
;
1234 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1236 UNICODE_STRING DriverName
;
1239 DPRINT("IopInitializeBootDrivers()\n");
1241 BootDriverCount
= 0;
1242 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1244 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1245 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1246 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1247 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1248 Extension
= strrchr(ModuleName
, '.');
1249 if (Extension
== NULL
)
1252 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1254 /* Process symbols for *.exe and *.dll */
1255 KDB_SYMBOLFILE_HOOK(ModuleName
);
1257 /* Log *.exe and *.dll files */
1258 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1259 IopBootLog(&DriverName
, TRUE
);
1260 RtlFreeUnicodeString(&DriverName
);
1262 else if (!_stricmp(Extension
, ".sys"))
1264 /* Initialize and log boot start driver */
1267 Status
= IopInitializeBuiltinDriver(NULL
,
1271 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1272 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1273 RtlFreeUnicodeString(&DriverName
);
1280 * Free memory for all boot files, except ntoskrnl.exe.
1282 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1284 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1285 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1288 KeLoaderBlock
.ModsCount
= 0;
1290 if (BootDriverCount
== 0)
1292 DbgPrint("No boot drivers available.\n");
1297 static INIT_FUNCTION NTSTATUS
1298 IopLoadDriver(PSERVICE Service
)
1300 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1302 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
);
1303 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1304 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1305 if (!NT_SUCCESS(Status
))
1307 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1309 if (Service
->ErrorControl
== 1)
1313 else if (Service
->ErrorControl
== 2)
1315 if (IsLastKnownGood
== FALSE
)
1317 /* Boot last known good configuration */
1320 else if (Service
->ErrorControl
== 3)
1322 if (IsLastKnownGood
== FALSE
)
1324 /* Boot last known good configuration */
1338 * IopInitializeSystemDrivers
1340 * Load drivers marked as system start.
1350 IopInitializeSystemDrivers(VOID
)
1352 PLIST_ENTRY GroupEntry
;
1353 PLIST_ENTRY ServiceEntry
;
1354 PSERVICE_GROUP CurrentGroup
;
1355 PSERVICE CurrentService
;
1359 DPRINT("IopInitializeSystemDrivers()\n");
1361 GroupEntry
= GroupListHead
.Flink
;
1362 while (GroupEntry
!= &GroupListHead
)
1364 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1366 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1368 /* Load all drivers with a valid tag */
1369 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1371 ServiceEntry
= ServiceListHead
.Flink
;
1372 while (ServiceEntry
!= &ServiceListHead
)
1374 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1376 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1377 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1378 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1379 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1381 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1382 Status
= IopLoadDriver(CurrentService
);
1384 ServiceEntry
= ServiceEntry
->Flink
;
1388 /* Load all drivers without a tag or with an invalid tag */
1389 ServiceEntry
= ServiceListHead
.Flink
;
1390 while (ServiceEntry
!= &ServiceListHead
)
1392 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1393 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1394 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1395 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1397 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1399 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1404 if (i
>= CurrentGroup
->TagCount
)
1406 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1407 Status
= IopLoadDriver(CurrentService
);
1410 ServiceEntry
= ServiceEntry
->Flink
;
1413 GroupEntry
= GroupEntry
->Flink
;
1416 DPRINT("IopInitializeSystemDrivers() done\n");
1422 * Unloads a device driver.
1426 * Name of the service to unload (registry key).
1429 * Whether to unload Plug & Plug or only legacy drivers. If this
1430 * parameter is set to FALSE, the routine will unload only legacy
1437 * Guard the whole function by SEH.
1441 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1443 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1444 UNICODE_STRING ImagePath
;
1445 UNICODE_STRING ServiceName
;
1446 UNICODE_STRING ObjectName
;
1447 PDRIVER_OBJECT DriverObject
;
1448 PMODULE_OBJECT ModuleObject
;
1452 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1455 * Get the service name from the registry key name
1458 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1460 Start
= DriverServiceName
->Buffer
;
1464 RtlInitUnicodeString(&ServiceName
, Start
);
1467 * Construct the driver object name
1470 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1471 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1472 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1473 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1474 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1475 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1478 * Find the driver object
1481 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1482 KernelMode
, 0, (PVOID
*)&DriverObject
);
1484 if (!NT_SUCCESS(Status
))
1486 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1491 * Free the buffer for driver object name
1494 ExFreePool(ObjectName
.Buffer
);
1497 * Get path of service...
1500 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1502 RtlInitUnicodeString(&ImagePath
, NULL
);
1504 QueryTable
[0].Name
= L
"ImagePath";
1505 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1506 QueryTable
[0].EntryContext
= &ImagePath
;
1508 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1509 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1511 if (!NT_SUCCESS(Status
))
1513 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1518 * Normalize the image path for all later processing.
1521 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1523 if (!NT_SUCCESS(Status
))
1525 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1530 * ... and check if it's loaded
1533 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1534 if (ModuleObject
== NULL
)
1536 return STATUS_UNSUCCESSFUL
;
1540 * Free the service path
1543 ExFreePool(ImagePath
.Buffer
);
1546 * Unload the module and release the references to the device object
1549 if (DriverObject
->DriverUnload
)
1550 (*DriverObject
->DriverUnload
)(DriverObject
);
1551 ObDereferenceObject(DriverObject
);
1552 ObDereferenceObject(DriverObject
);
1553 LdrUnloadModule(ModuleObject
);
1555 return STATUS_SUCCESS
;
1559 IopMarkLastReinitializeDriver(VOID
)
1563 KeAcquireSpinLock(&DriverReinitListLock
,
1566 if (IsListEmpty(&DriverReinitListHead
))
1568 DriverReinitTailEntry
= NULL
;
1572 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1575 KeReleaseSpinLock(&DriverReinitListLock
,
1581 IopReinitializeDrivers(VOID
)
1583 PDRIVER_REINIT_ITEM ReinitItem
;
1587 KeAcquireSpinLock(&DriverReinitListLock
,
1590 if (DriverReinitTailEntry
== NULL
)
1592 KeReleaseSpinLock(&DriverReinitListLock
,
1597 KeReleaseSpinLock(&DriverReinitListLock
,
1602 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1603 &DriverReinitListLock
);
1607 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1609 /* Increment reinitialization counter */
1610 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1612 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1613 ReinitItem
->Context
,
1614 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1618 if (Entry
== DriverReinitTailEntry
)
1623 /* PUBLIC FUNCTIONS ***********************************************************/
1632 IN PUNICODE_STRING DriverName
, OPTIONAL
1633 IN PDRIVER_INITIALIZE InitializationFunction
1636 WCHAR NameBuffer
[100];
1638 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1640 OBJECT_ATTRIBUTES ObjectAttributes
;
1642 PDRIVER_OBJECT DriverObject
;
1643 UNICODE_STRING ServiceKeyName
;
1647 /* First, create a unique name for the driver if we don't have one */
1650 /* Create a random name and set up the string*/
1651 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1652 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1653 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1654 LocalDriverName
.Buffer
= NameBuffer
;
1658 /* So we can avoid another code path, use a local var */
1659 LocalDriverName
= *DriverName
;
1662 /* Initialize the Attributes */
1663 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1664 InitializeObjectAttributes(&ObjectAttributes
,
1666 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1670 /* Create the Object */
1671 Status
= ObCreateObject(KernelMode
,
1679 (PVOID
*)&DriverObject
);
1681 /* Return on failure */
1682 if (!NT_SUCCESS(Status
)) return Status
;
1684 /* Set up the Object */
1685 RtlZeroMemory(DriverObject
, ObjectSize
);
1686 DriverObject
->Type
= IO_TYPE_DRIVER
;
1687 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1688 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1689 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1690 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1691 DriverObject
->DriverInit
= InitializationFunction
;
1693 /* Invalidate all Major Functions */
1694 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1696 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1699 /* Set up the Service Key Name */
1700 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1701 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1702 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1703 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1704 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1705 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1707 /* Also store it in the Driver Object. This is a bit of a hack. */
1708 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1710 /* Add the Object and get its handle */
1711 Status
= ObInsertObject(DriverObject
,
1718 /* Return on Failure */
1719 if (!NT_SUCCESS(Status
)) return Status
;
1721 /* Now reference it */
1722 Status
= ObReferenceObjectByHandle(hDriver
,
1726 (PVOID
*)&DriverObject
,
1730 /* Finally, call its init function */
1731 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1733 if (!NT_SUCCESS(Status
)) {
1734 /* If it didn't work, then kill the object */
1735 ObMakeTemporaryObject(DriverObject
);
1736 ObDereferenceObject(DriverObject
);
1739 /* Return the Status */
1749 IN PDRIVER_OBJECT DriverObject
1752 /* Simply derefence the Object */
1753 ObDereferenceObject(DriverObject
);
1760 * Loads a device driver.
1764 * Name of the service to load (registry key).
1774 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1776 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1777 UNICODE_STRING ImagePath
;
1778 UNICODE_STRING ServiceName
;
1779 UNICODE_STRING CapturedDriverServiceName
;
1780 KPROCESSOR_MODE PreviousMode
;
1783 PDEVICE_NODE DeviceNode
;
1784 PMODULE_OBJECT ModuleObject
;
1785 PDRIVER_OBJECT DriverObject
;
1790 PreviousMode
= KeGetPreviousMode();
1793 * Check security privileges
1796 /* FIXME: Uncomment when privileges will be correctly implemented. */
1798 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1800 DPRINT("Privilege not held\n");
1801 return STATUS_PRIVILEGE_NOT_HELD
;
1805 Status
= RtlCaptureUnicodeString(&CapturedDriverServiceName
,
1810 if (!NT_SUCCESS(Status
))
1815 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1817 RtlInitUnicodeString(&ImagePath
, NULL
);
1820 * Get the service name from the registry key name.
1822 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1824 ServiceName
= CapturedDriverServiceName
;
1825 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1826 while (CapturedDriverServiceName
.Buffer
!= cur
)
1830 ServiceName
.Buffer
= cur
+ 1;
1831 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1832 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1833 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1843 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1845 RtlInitUnicodeString(&ImagePath
, NULL
);
1847 QueryTable
[0].Name
= L
"Type";
1848 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1849 QueryTable
[0].EntryContext
= &Type
;
1851 QueryTable
[1].Name
= L
"ImagePath";
1852 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1853 QueryTable
[1].EntryContext
= &ImagePath
;
1855 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1856 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1858 if (!NT_SUCCESS(Status
))
1860 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1861 ExFreePool(ImagePath
.Buffer
);
1862 goto ReleaseCapturedString
;
1866 * Normalize the image path for all later processing.
1869 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1871 if (!NT_SUCCESS(Status
))
1873 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1874 goto ReleaseCapturedString
;
1877 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1878 DPRINT("Type: %lx\n", Type
);
1881 * See, if the driver module isn't already loaded
1884 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1885 if (ModuleObject
!= NULL
)
1887 DPRINT("Image already loaded\n");
1888 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1889 goto ReleaseCapturedString
;
1893 * Create device node
1896 /* Use IopRootDeviceNode for now */
1897 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1899 if (!NT_SUCCESS(Status
))
1901 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1902 goto ReleaseCapturedString
;
1906 * Load the driver module
1909 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1911 if (!NT_SUCCESS(Status
))
1913 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1914 IopFreeDeviceNode(DeviceNode
);
1915 goto ReleaseCapturedString
;
1919 * Set a service name for the device node
1922 RtlpCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
, NonPagedPool
);
1925 * Initialize the driver module
1928 Status
= IopInitializeDriverModule(
1931 &DeviceNode
->ServiceName
,
1932 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1933 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1936 if (!NT_SUCCESS(Status
))
1938 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1939 LdrUnloadModule(ModuleObject
);
1940 IopFreeDeviceNode(DeviceNode
);
1941 goto ReleaseCapturedString
;
1944 IopInitializeDevice(DeviceNode
, DriverObject
);
1946 ReleaseCapturedString
:
1947 RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1957 * Unloads a legacy device driver.
1961 * Name of the service to unload (registry key).
1971 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1973 return IopUnloadDriver(DriverServiceName
, FALSE
);
1977 * IoRegisterDriverReinitialization
1984 IoRegisterDriverReinitialization(
1985 PDRIVER_OBJECT DriverObject
,
1986 PDRIVER_REINITIALIZE ReinitRoutine
,
1989 PDRIVER_REINIT_ITEM ReinitItem
;
1991 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
1992 if (ReinitItem
== NULL
)
1995 ReinitItem
->DriverObject
= DriverObject
;
1996 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1997 ReinitItem
->Context
= Context
;
1999 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2001 ExInterlockedInsertTailList(
2002 &DriverReinitListHead
,
2003 &ReinitItem
->ItemEntry
,
2004 &DriverReinitListLock
);
2012 IoRegisterBootDriverReinitialization(
2013 IN PDRIVER_OBJECT DriverObject
,
2014 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2018 PDRIVER_REINIT_ITEM ReinitItem
;
2020 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2021 if (ReinitItem
== NULL
)
2024 ReinitItem
->DriverObject
= DriverObject
;
2025 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2026 ReinitItem
->Context
= Context
;
2028 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2030 ExInterlockedInsertTailList(
2031 &DriverBootReinitListHead
,
2032 &ReinitItem
->ItemEntry
,
2033 &DriverReinitListLock
);
2037 * IoAllocateDriverObjectExtension
2044 IoAllocateDriverObjectExtension(
2045 PDRIVER_OBJECT DriverObject
,
2046 PVOID ClientIdentificationAddress
,
2047 ULONG DriverObjectExtensionSize
,
2048 PVOID
*DriverObjectExtension
)
2051 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2052 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2054 NewDriverExtension
= ExAllocatePoolWithTag(
2056 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2057 DriverObjectExtensionSize
,
2058 TAG_DRIVER_EXTENSION
);
2060 if (NewDriverExtension
== NULL
)
2062 return STATUS_INSUFFICIENT_RESOURCES
;
2065 OldIrql
= KeRaiseIrqlToDpcLevel();
2067 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2068 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2070 for (DriverExtensions
= DriverObject
->DriverSection
;
2071 DriverExtensions
!= NULL
;
2072 DriverExtensions
= DriverExtensions
->Link
)
2074 if (DriverExtensions
->ClientIdentificationAddress
==
2075 ClientIdentificationAddress
)
2077 KfLowerIrql(OldIrql
);
2078 return STATUS_OBJECT_NAME_COLLISION
;
2082 DriverObject
->DriverSection
= NewDriverExtension
;
2084 KfLowerIrql(OldIrql
);
2086 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2088 return STATUS_SUCCESS
;
2092 * IoGetDriverObjectExtension
2099 IoGetDriverObjectExtension(
2100 PDRIVER_OBJECT DriverObject
,
2101 PVOID ClientIdentificationAddress
)
2104 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2106 OldIrql
= KeRaiseIrqlToDpcLevel();
2108 for (DriverExtensions
= DriverObject
->DriverSection
;
2109 DriverExtensions
!= NULL
&&
2110 DriverExtensions
->ClientIdentificationAddress
!=
2111 ClientIdentificationAddress
;
2112 DriverExtensions
= DriverExtensions
->Link
)
2115 KfLowerIrql(OldIrql
);
2117 if (DriverExtensions
== NULL
)
2120 return &DriverExtensions
->Extension
;