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
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * Filip Navara (xnavara@volny.cz)
13 /* INCLUDES *******************************************************************/
17 #include <internal/debug.h>
20 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock
;
21 extern ULONG KeTickCount
;
24 LdrProcessModule(PVOID ModuleLoadBase
,
25 PUNICODE_STRING ModuleName
,
26 PMODULE_OBJECT
*ModuleObject
);
28 typedef struct _SERVICE_GROUP
30 LIST_ENTRY GroupListEntry
;
31 UNICODE_STRING GroupName
;
32 BOOLEAN ServicesRunning
;
35 } SERVICE_GROUP
, *PSERVICE_GROUP
;
37 typedef struct _SERVICE
39 LIST_ENTRY ServiceListEntry
;
40 UNICODE_STRING ServiceName
;
41 UNICODE_STRING RegistryPath
;
42 UNICODE_STRING ServiceGroup
;
43 UNICODE_STRING ImagePath
;
50 /* BOOLEAN ServiceRunning;*/ // needed ??
53 typedef struct _DRIVER_REINIT_ITEM
56 PDRIVER_OBJECT DriverObject
;
57 PDRIVER_REINITIALIZE ReinitRoutine
;
59 } DRIVER_REINIT_ITEM
, *PDRIVER_REINIT_ITEM
;
61 /* GLOBALS ********************************************************************/
63 static LIST_ENTRY DriverReinitListHead
;
64 static PLIST_ENTRY DriverReinitTailEntry
;
65 static KSPIN_LOCK DriverReinitListLock
;
67 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
68 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
70 static UNICODE_STRING IopHardwareDatabaseKey
=
71 ROS_STRING_INITIALIZER(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
73 POBJECT_TYPE EXPORTED IoDriverObjectType
= NULL
;
75 #define TAG_DRIVER TAG('D', 'R', 'V', 'R')
76 #define TAG_DRIVER_EXTENSION TAG('D', 'R', 'V', 'E')
78 /* DECLARATIONS ***************************************************************/
85 POBJECT_ATTRIBUTES ObjectAttributes
);
88 IopDeleteDriver(PVOID ObjectBody
);
90 /* PRIVATE FUNCTIONS **********************************************************/
93 IopInitDriverImplementation(VOID
)
95 /* Register the process object type */
96 IoDriverObjectType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
97 IoDriverObjectType
->Tag
= TAG('D', 'R', 'V', 'R');
98 IoDriverObjectType
->TotalObjects
= 0;
99 IoDriverObjectType
->TotalHandles
= 0;
100 IoDriverObjectType
->PeakObjects
= 0;
101 IoDriverObjectType
->PeakHandles
= 0;
102 IoDriverObjectType
->PagedPoolCharge
= 0;
103 IoDriverObjectType
->NonpagedPoolCharge
= sizeof(DRIVER_OBJECT
);
104 IoDriverObjectType
->Dump
= NULL
;
105 IoDriverObjectType
->Open
= NULL
;
106 IoDriverObjectType
->Close
= NULL
;
107 IoDriverObjectType
->Delete
= IopDeleteDriver
;
108 IoDriverObjectType
->Parse
= NULL
;
109 IoDriverObjectType
->Security
= NULL
;
110 IoDriverObjectType
->QueryName
= NULL
;
111 IoDriverObjectType
->OkayToClose
= NULL
;
112 IoDriverObjectType
->Create
= IopCreateDriver
;
113 IoDriverObjectType
->DuplicationNotify
= NULL
;
114 RtlRosInitUnicodeStringFromLiteral(&IoDriverObjectType
->TypeName
, L
"Driver");
116 ObpCreateTypeObject(IoDriverObjectType
);
118 InitializeListHead(&DriverReinitListHead
);
119 KeInitializeSpinLock(&DriverReinitListLock
);
120 DriverReinitTailEntry
= NULL
;
124 IopInvalidDeviceRequest(
125 PDEVICE_OBJECT DeviceObject
,
128 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
129 Irp
->IoStatus
.Information
= 0;
130 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
131 return STATUS_INVALID_DEVICE_REQUEST
;
139 POBJECT_ATTRIBUTES ObjectAttributes
)
141 PDRIVER_OBJECT Object
= ObjectBody
;
144 DPRINT("IopCreateDriver(ObjectBody %x, Parent %x, RemainingPath %S)\n",
145 ObjectBody
, Parent
, RemainingPath
);
147 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+ 1, '\\') != NULL
)
148 return STATUS_UNSUCCESSFUL
;
150 /* Create driver extension */
151 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
152 ExAllocatePoolWithTag(
154 sizeof(DRIVER_EXTENSION
),
155 TAG_DRIVER_EXTENSION
);
157 if (Object
->DriverExtension
== NULL
)
159 return STATUS_NO_MEMORY
;
162 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
164 Object
->Type
= InternalDriverType
;
166 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
167 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
169 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
171 return STATUS_SUCCESS
;
175 IopDeleteDriver(PVOID ObjectBody
)
177 PDRIVER_OBJECT Object
= ObjectBody
;
179 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
181 DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody
);
183 ExFreePool(Object
->DriverExtension
);
184 RtlFreeUnicodeString(&Object
->DriverName
);
186 OldIrql
= KeRaiseIrqlToDpcLevel();
188 for (DriverExtension
= Object
->DriverSection
;
189 DriverExtension
!= NULL
;
190 DriverExtension
= NextDriverExtension
)
192 NextDriverExtension
= DriverExtension
->Link
;
193 ExFreePool(DriverExtension
);
196 KfLowerIrql(OldIrql
);
200 IopCreateDriverObject(
201 PDRIVER_OBJECT
*DriverObject
,
202 PUNICODE_STRING ServiceName
,
204 PVOID DriverImageStart
,
205 ULONG DriverImageSize
)
207 PDRIVER_OBJECT Object
;
208 WCHAR NameBuffer
[MAX_PATH
];
209 UNICODE_STRING DriverName
;
210 OBJECT_ATTRIBUTES ObjectAttributes
;
214 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
215 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
217 *DriverObject
= NULL
;
219 /* Create ModuleName string */
220 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
222 if (FileSystem
== TRUE
)
223 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
225 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
226 wcscat(NameBuffer
, ServiceName
->Buffer
);
228 RtlInitUnicodeString(&DriverName
, NameBuffer
);
229 DPRINT("Driver name: '%wZ'\n", &DriverName
);
231 Buffer
= (PWSTR
)ExAllocatePool(NonPagedPool
, DriverName
.Length
);
232 /* If we don't success, it is not a problem. Our driver
233 * object will not have associated driver name... */
237 RtlInitUnicodeString(&DriverName
, NULL
);
240 /* Initialize ObjectAttributes for driver object */
241 InitializeObjectAttributes(
248 /* Create driver object */
249 Status
= ObCreateObject(
255 sizeof(DRIVER_OBJECT
),
260 if (!NT_SUCCESS(Status
))
265 Object
->DriverStart
= DriverImageStart
;
266 Object
->DriverSize
= DriverImageSize
;
269 Object
->DriverName
.Buffer
= Buffer
;
270 Object
->DriverName
.Length
= Object
->DriverName
.MaximumLength
= DriverName
.Length
;
271 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
274 *DriverObject
= Object
;
276 return STATUS_SUCCESS
;
280 * IopDisplayLoadingMessage
282 * Display 'Loading XXX...' message.
286 IopDisplayLoadingMessage(PWCHAR ServiceName
)
288 CHAR TextBuffer
[256];
289 sprintf(TextBuffer
, "Loading %S...\n", ServiceName
);
290 HalDisplayString(TextBuffer
);
294 * IopNormalizeImagePath
296 * Normalize an image path to contain complete path.
300 * The input path and on exit the result path. ImagePath.Buffer
301 * must be allocated by ExAllocatePool on input. Caller is responsible
302 * for freeing the buffer when it's no longer needed.
305 * Name of the service that ImagePath belongs to.
311 * The input image path isn't freed on error.
315 IopNormalizeImagePath(
316 IN OUT PUNICODE_STRING ImagePath
,
317 IN PUNICODE_STRING ServiceName
)
319 UNICODE_STRING InputImagePath
;
324 sizeof(UNICODE_STRING
));
326 if (InputImagePath
.Length
== 0)
328 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
329 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
330 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
331 if (ImagePath
->Buffer
== NULL
)
332 return STATUS_NO_MEMORY
;
334 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
335 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
336 wcscat(ImagePath
->Buffer
, L
".sys");
338 if (InputImagePath
.Buffer
[0] != L
'\\')
340 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
341 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
342 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
343 if (ImagePath
->Buffer
== NULL
)
344 return STATUS_NO_MEMORY
;
346 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
347 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
348 RtlFreeUnicodeString(&InputImagePath
);
351 return STATUS_SUCCESS
;
355 * IopLoadServiceModule
357 * Load a module specified by registry settings for service.
361 * Name of the service to load.
368 IopLoadServiceModule(
369 IN PUNICODE_STRING ServiceName
,
370 OUT PMODULE_OBJECT
*ModuleObject
)
372 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
374 UNICODE_STRING ServiceImagePath
;
377 DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName
, ModuleObject
);
380 * Get information about the service.
383 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
385 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
387 QueryTable
[0].Name
= L
"Start";
388 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
389 QueryTable
[0].EntryContext
= &ServiceStart
;
391 QueryTable
[1].Name
= L
"ImagePath";
392 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
393 QueryTable
[1].EntryContext
= &ServiceImagePath
;
395 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
396 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
398 if (!NT_SUCCESS(Status
))
400 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
404 IopDisplayLoadingMessage(ServiceName
->Buffer
);
407 * Normalize the image path for all later processing.
410 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
412 if (!NT_SUCCESS(Status
))
414 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
422 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
424 if (*ModuleObject
== NULL
)
426 Status
= STATUS_UNSUCCESSFUL
;
429 * Special case for boot modules that were loaded by boot loader.
432 if (ServiceStart
== 0)
435 CHAR SearchName
[256];
437 PLOADER_MODULE KeLoaderModules
=
438 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
442 * Improve this searching algorithm by using the image name
443 * stored in registry entry ImageName and use the whole path
444 * (requires change in FreeLoader).
447 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
448 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
450 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
451 if (!_stricmp(ModuleName
, SearchName
))
453 DPRINT("Initializing boot module\n");
455 /* Tell, that the module is already loaded */
456 KeLoaderModules
[i
].Reserved
= 1;
458 Status
= LdrProcessModule(
459 (PVOID
)KeLoaderModules
[i
].ModStart
,
463 KDB_SYMBOLFILE_HOOK(SearchName
);
471 * Case for rest of the drivers (except disabled)
474 else if (ServiceStart
< 4)
476 DPRINT("Loading module\n");
477 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
482 DPRINT("Module already loaded\n");
483 Status
= STATUS_SUCCESS
;
486 RtlFreeUnicodeString(&ServiceImagePath
);
489 * Now check if the module was loaded successfully.
492 if (!NT_SUCCESS(Status
))
494 DPRINT("Module loading failed (Status %x)\n", Status
);
497 DPRINT("Module loading (Status %x)\n", Status
);
503 * IopInitializeDriverModule
505 * Initalize a loaded driver.
509 * Pointer to device node.
512 * Module object representing the driver. It can be retrieve by
513 * IopLoadServiceModule.
516 * Set to TRUE for file system drivers.
519 * On successful return this contains the driver object representing
524 IopInitializeDriverModule(
525 IN PDEVICE_NODE DeviceNode
,
526 IN PMODULE_OBJECT ModuleObject
,
527 IN BOOLEAN FileSystemDriver
,
528 OUT PDRIVER_OBJECT
*DriverObject
)
530 UNICODE_STRING RegistryKey
;
531 PDRIVER_INITIALIZE DriverEntry
= ModuleObject
->EntryPoint
;
533 WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
535 Status
= IopCreateDriverObject(
537 &DeviceNode
->ServiceName
,
540 ModuleObject
->Length
);
542 if (!NT_SUCCESS(Status
))
544 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
548 if (DeviceNode
->ServiceName
.Buffer
)
550 RegistryKey
.Length
= DeviceNode
->ServiceName
.Length
+
551 sizeof(ServicesKeyName
) - sizeof(UNICODE_NULL
);
552 RegistryKey
.MaximumLength
= RegistryKey
.Length
+ sizeof(UNICODE_NULL
);
553 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
554 wcscpy(RegistryKey
.Buffer
, ServicesKeyName
);
555 wcscat(RegistryKey
.Buffer
, DeviceNode
->ServiceName
.Buffer
);
559 RtlInitUnicodeString(&RegistryKey
, NULL
);
562 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
563 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
565 IopMarkLastReinitializeDriver();
567 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
568 if (!NT_SUCCESS(Status
))
570 ObMakeTemporaryObject(*DriverObject
);
571 ObDereferenceObject(*DriverObject
);
575 IopReinitializeDrivers();
577 return STATUS_SUCCESS
;
581 * IopAttachFilterDriversCallback
583 * Internal routine used by IopAttachFilterDrivers.
587 IopAttachFilterDriversCallback(
595 PDEVICE_NODE DeviceNode
= Context
;
596 UNICODE_STRING ServiceName
;
598 PMODULE_OBJECT ModuleObject
;
599 PDRIVER_OBJECT DriverObject
;
602 for (Filters
= ValueData
;
603 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
605 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
607 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
608 ServiceName
.Buffer
= Filters
;
609 ServiceName
.MaximumLength
=
610 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
612 /* Load and initialize the filter driver */
613 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
614 if (!NT_SUCCESS(Status
))
617 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, FALSE
, &DriverObject
);
618 if (!NT_SUCCESS(Status
))
621 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
622 if (!NT_SUCCESS(Status
))
626 return STATUS_SUCCESS
;
630 * IopAttachFilterDrivers
632 * Load filter drivers for specified device node.
636 * Set to TRUE for loading lower level filters or FALSE for upper
641 IopAttachFilterDrivers(
642 PDEVICE_NODE DeviceNode
,
645 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
647 UNICODE_STRING Class
;
648 WCHAR ClassBuffer
[40];
652 * First load the device filters
655 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
657 QueryTable
[0].Name
= L
"LowerFilters";
659 QueryTable
[0].Name
= L
"UpperFilters";
660 QueryTable
[0].EntryContext
= NULL
;
661 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
662 QueryTable
[1].QueryRoutine
= NULL
;
663 QueryTable
[1].Name
= NULL
;
665 KeyBuffer
= ExAllocatePool(
667 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
668 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
669 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
671 RtlQueryRegistryValues(
672 RTL_REGISTRY_ABSOLUTE
,
679 * Now get the class GUID
683 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
684 Class
.Buffer
= ClassBuffer
;
685 QueryTable
[0].QueryRoutine
= NULL
;
686 QueryTable
[0].Name
= L
"ClassGUID";
687 QueryTable
[0].EntryContext
= &Class
;
688 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
690 Status
= RtlQueryRegistryValues(
691 RTL_REGISTRY_ABSOLUTE
,
697 ExFreePool(KeyBuffer
);
700 * Load the class filter driver
703 if (NT_SUCCESS(Status
))
705 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
707 QueryTable
[0].Name
= L
"LowerFilters";
709 QueryTable
[0].Name
= L
"UpperFilters";
710 QueryTable
[0].EntryContext
= NULL
;
711 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
713 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
714 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
715 wcscat(KeyBuffer
, ClassBuffer
);
717 RtlQueryRegistryValues(
718 RTL_REGISTRY_ABSOLUTE
,
724 ExFreePool(KeyBuffer
);
727 return STATUS_SUCCESS
;
730 static NTSTATUS STDCALL
731 IopGetGroupOrderList(PWSTR ValueName
,
738 PSERVICE_GROUP Group
;
740 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
741 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
743 if (ValueType
== REG_BINARY
&&
745 ValueLength
>= sizeof(DWORD
) &&
746 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
748 Group
= (PSERVICE_GROUP
)Context
;
749 Group
->TagCount
= ((PULONG
)ValueData
)[0];
750 if (Group
->TagCount
> 0)
752 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
754 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
755 if (Group
->TagArray
== NULL
)
758 return STATUS_INSUFFICIENT_RESOURCES
;
760 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
765 return STATUS_UNSUCCESSFUL
;
769 return STATUS_SUCCESS
;
772 static NTSTATUS STDCALL
773 IopCreateGroupListEntry(PWSTR ValueName
,
780 PSERVICE_GROUP Group
;
781 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
785 if (ValueType
== REG_SZ
)
787 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
789 Group
= ExAllocatePool(NonPagedPool
,
790 sizeof(SERVICE_GROUP
));
793 return(STATUS_INSUFFICIENT_RESOURCES
);
796 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
798 if (!RtlCreateUnicodeString(&Group
->GroupName
,
802 return(STATUS_INSUFFICIENT_RESOURCES
);
805 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
806 QueryTable
[0].Name
= (PWSTR
)ValueData
;
807 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
809 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
814 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
816 InsertTailList(&GroupListHead
,
817 &Group
->GroupListEntry
);
820 return(STATUS_SUCCESS
);
824 static NTSTATUS STDCALL
825 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
827 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
831 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
833 /* Allocate service entry */
834 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
837 DPRINT1("ExAllocatePool() failed\n");
838 return(STATUS_INSUFFICIENT_RESOURCES
);
840 RtlZeroMemory(Service
, sizeof(SERVICE
));
842 /* Get service data */
843 RtlZeroMemory(&QueryTable
,
846 QueryTable
[0].Name
= L
"Start";
847 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
848 QueryTable
[0].EntryContext
= &Service
->Start
;
850 QueryTable
[1].Name
= L
"Type";
851 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
852 QueryTable
[1].EntryContext
= &Service
->Type
;
854 QueryTable
[2].Name
= L
"ErrorControl";
855 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
856 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
858 QueryTable
[3].Name
= L
"Group";
859 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
860 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
862 QueryTable
[4].Name
= L
"ImagePath";
863 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
864 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
866 QueryTable
[5].Name
= L
"Tag";
867 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
868 QueryTable
[5].EntryContext
= &Service
->Tag
;
870 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
875 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
877 RtlFreeUnicodeString(&Service
->ServiceGroup
);
878 RtlFreeUnicodeString(&Service
->ImagePath
);
883 /* Copy service name */
884 Service
->ServiceName
.Length
= ServiceName
->Length
;
885 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
886 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
887 Service
->ServiceName
.MaximumLength
);
888 RtlCopyMemory(Service
->ServiceName
.Buffer
,
890 ServiceName
->Length
);
891 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
893 /* Build registry path */
894 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
895 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
896 MAX_PATH
* sizeof(WCHAR
));
897 wcscpy(Service
->RegistryPath
.Buffer
,
898 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
899 wcscat(Service
->RegistryPath
.Buffer
,
900 Service
->ServiceName
.Buffer
);
901 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
903 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
904 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
905 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
906 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
907 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
908 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
910 /* Append service entry */
911 InsertTailList(&ServiceListHead
,
912 &Service
->ServiceListEntry
);
914 return(STATUS_SUCCESS
);
918 NTSTATUS INIT_FUNCTION
919 IoCreateDriverList(VOID
)
921 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
922 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
923 OBJECT_ATTRIBUTES ObjectAttributes
;
924 UNICODE_STRING ServicesKeyName
;
925 UNICODE_STRING SubKeyName
;
930 ULONG KeyInfoLength
= 0;
931 ULONG ReturnedLength
;
933 DPRINT("IoCreateDriverList() called\n");
935 /* Initialize basic variables */
936 InitializeListHead(&GroupListHead
);
937 InitializeListHead(&ServiceListHead
);
939 /* Build group order list */
940 RtlZeroMemory(&QueryTable
,
943 QueryTable
[0].Name
= L
"List";
944 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
946 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
947 L
"ServiceGroupOrder",
951 if (!NT_SUCCESS(Status
))
954 /* Enumerate services and create the service list */
955 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
956 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
958 InitializeObjectAttributes(&ObjectAttributes
,
960 OBJ_CASE_INSENSITIVE
,
964 Status
= NtOpenKey(&KeyHandle
,
967 if (!NT_SUCCESS(Status
))
972 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
973 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
977 return(STATUS_INSUFFICIENT_RESOURCES
);
983 Status
= NtEnumerateKey(KeyHandle
,
989 if (NT_SUCCESS(Status
))
991 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
994 SubKeyName
.Length
= KeyInfo
->NameLength
;
995 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
996 SubKeyName
.Buffer
= KeyInfo
->Name
;
997 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
999 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1000 IopCreateServiceListEntry(&SubKeyName
);
1004 if (!NT_SUCCESS(Status
))
1010 ExFreePool(KeyInfo
);
1013 DPRINT("IoCreateDriverList() done\n");
1015 return(STATUS_SUCCESS
);
1018 NTSTATUS INIT_FUNCTION
1019 IoDestroyDriverList(VOID
)
1021 PLIST_ENTRY GroupEntry
;
1022 PLIST_ENTRY ServiceEntry
;
1023 PSERVICE_GROUP CurrentGroup
;
1024 PSERVICE CurrentService
;
1026 DPRINT("IoDestroyDriverList() called\n");
1028 /* Destroy group list */
1029 GroupEntry
= GroupListHead
.Flink
;
1030 while (GroupEntry
!= &GroupListHead
)
1032 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1034 RtlFreeUnicodeString(&CurrentGroup
->GroupName
);
1035 RemoveEntryList(GroupEntry
);
1036 if (CurrentGroup
->TagArray
)
1038 ExFreePool(CurrentGroup
->TagArray
);
1040 ExFreePool(CurrentGroup
);
1042 GroupEntry
= GroupListHead
.Flink
;
1045 /* Destroy service list */
1046 ServiceEntry
= ServiceListHead
.Flink
;
1047 while (ServiceEntry
!= &ServiceListHead
)
1049 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1051 RtlFreeUnicodeString(&CurrentService
->ServiceName
);
1052 RtlFreeUnicodeString(&CurrentService
->RegistryPath
);
1053 RtlFreeUnicodeString(&CurrentService
->ServiceGroup
);
1054 RtlFreeUnicodeString(&CurrentService
->ImagePath
);
1055 RemoveEntryList(ServiceEntry
);
1056 ExFreePool(CurrentService
);
1058 ServiceEntry
= ServiceListHead
.Flink
;
1061 DPRINT("IoDestroyDriverList() done\n");
1063 return(STATUS_SUCCESS
);
1066 VOID STATIC INIT_FUNCTION
1067 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1071 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1073 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1078 * IopInitializeBuiltinDriver
1080 * Initialize a driver that is already loaded in memory.
1083 NTSTATUS FASTCALL INIT_FUNCTION
1084 IopInitializeBuiltinDriver(
1085 PDEVICE_NODE ModuleDeviceNode
,
1086 PVOID ModuleLoadBase
,
1090 PMODULE_OBJECT ModuleObject
;
1091 PDEVICE_NODE DeviceNode
;
1092 PDRIVER_OBJECT DriverObject
;
1094 CHAR TextBuffer
[256];
1095 PCHAR FileNameWithoutPath
;
1096 LPWSTR FileExtension
;
1098 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1099 FileName
, ModuleLoadBase
, ModuleLength
);
1102 * Display 'Initializing XXX...' message
1105 sprintf(TextBuffer
, "Initializing %s...\n", FileName
);
1106 HalDisplayString(TextBuffer
);
1109 * Determine the right device object
1112 if (ModuleDeviceNode
== NULL
)
1114 /* Use IopRootDeviceNode for now */
1115 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1116 if (!NT_SUCCESS(Status
))
1118 CPRINT("Driver load failed, status (%x)\n", Status
);
1123 DeviceNode
= ModuleDeviceNode
;
1127 * Generate filename without path (not needed by freeldr)
1130 FileNameWithoutPath
= strrchr(FileName
, '\\');
1131 if (FileNameWithoutPath
== NULL
)
1133 FileNameWithoutPath
= FileName
;
1140 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1141 FileNameWithoutPath
);
1142 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1144 if (!NT_SUCCESS(Status
))
1146 if (ModuleDeviceNode
== NULL
)
1147 IopFreeDeviceNode(DeviceNode
);
1148 CPRINT("Driver load failed, status (%x)\n", Status
);
1153 KDB_SYMBOLFILE_HOOK(FileName
);
1156 * Strip the file extension from ServiceName
1159 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1160 if (FileExtension
!= NULL
)
1162 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1163 FileExtension
[0] = 0;
1167 * Initialize the driver
1170 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, FALSE
,
1173 if (!NT_SUCCESS(Status
))
1175 if (ModuleDeviceNode
== NULL
)
1176 IopFreeDeviceNode(DeviceNode
);
1177 CPRINT("Driver load failed, status (%x)\n", Status
);
1181 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1187 * IopInitializeBootDrivers
1189 * Initialize boot drivers and free memory for boot files.
1199 IopInitializeBootDrivers(VOID
)
1201 ULONG BootDriverCount
;
1207 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1209 UNICODE_STRING DriverName
;
1212 DPRINT("IopInitializeBootDrivers()\n");
1214 BootDriverCount
= 0;
1215 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1217 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1218 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1219 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1220 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1221 Extension
= strrchr(ModuleName
, '.');
1222 if (Extension
== NULL
)
1225 if (!_stricmp(Extension
, ".exe") || !_stricmp(Extension
, ".dll"))
1227 /* Process symbols for *.exe and *.dll */
1228 KDB_SYMBOLFILE_HOOK(ModuleName
);
1230 /* Log *.exe and *.dll files */
1231 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1232 IopBootLog(&DriverName
, TRUE
);
1233 RtlFreeUnicodeString(&DriverName
);
1235 else if (!_stricmp(Extension
, ".sys"))
1237 /* Initialize and log boot start driver */
1240 Status
= IopInitializeBuiltinDriver(NULL
,
1244 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1245 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1246 RtlFreeUnicodeString(&DriverName
);
1253 * Free memory for all boot files, except ntoskrnl.exe.
1255 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1258 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1259 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1262 if (BootDriverCount
== 0)
1264 DbgPrint("No boot drivers available.\n");
1269 static INIT_FUNCTION NTSTATUS
1270 IopLoadDriver(PSERVICE Service
)
1272 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1274 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
);
1275 Status
= NtLoadDriver(&Service
->RegistryPath
);
1276 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1277 if (!NT_SUCCESS(Status
))
1279 DPRINT("NtLoadDriver() failed (Status %lx)\n", Status
);
1281 if (Service
->ErrorControl
== 1)
1285 else if (Service
->ErrorControl
== 2)
1287 if (IsLastKnownGood
== FALSE
)
1289 /* Boot last known good configuration */
1292 else if (Service
->ErrorControl
== 3)
1294 if (IsLastKnownGood
== FALSE
)
1296 /* Boot last known good configuration */
1310 * IopInitializeSystemDrivers
1312 * Load drivers marked as system start.
1322 IopInitializeSystemDrivers(VOID
)
1324 PLIST_ENTRY GroupEntry
;
1325 PLIST_ENTRY ServiceEntry
;
1326 PSERVICE_GROUP CurrentGroup
;
1327 PSERVICE CurrentService
;
1331 DPRINT("IopInitializeSystemDrivers()\n");
1333 GroupEntry
= GroupListHead
.Flink
;
1334 while (GroupEntry
!= &GroupListHead
)
1336 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1338 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1340 /* Load all drivers with a valid tag */
1341 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1343 ServiceEntry
= ServiceListHead
.Flink
;
1344 while (ServiceEntry
!= &ServiceListHead
)
1346 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1348 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1349 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1350 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1351 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1353 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1354 Status
= IopLoadDriver(CurrentService
);
1356 ServiceEntry
= ServiceEntry
->Flink
;
1360 /* Load all drivers without a tag or with an invalid tag */
1361 ServiceEntry
= ServiceListHead
.Flink
;
1362 while (ServiceEntry
!= &ServiceListHead
)
1364 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1365 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1366 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1367 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1369 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1371 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1376 if (i
>= CurrentGroup
->TagCount
)
1378 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1379 Status
= IopLoadDriver(CurrentService
);
1382 ServiceEntry
= ServiceEntry
->Flink
;
1385 GroupEntry
= GroupEntry
->Flink
;
1388 DPRINT("IopInitializeSystemDrivers() done\n");
1394 * Unloads a device driver.
1398 * Name of the service to unload (registry key).
1401 * Whether to unload Plug & Plug or only legacy drivers. If this
1402 * parameter is set to FALSE, the routine will unload only legacy
1409 * Guard the whole function by SEH.
1413 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1415 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1416 UNICODE_STRING ImagePath
;
1417 UNICODE_STRING ServiceName
;
1418 UNICODE_STRING ObjectName
;
1419 PDRIVER_OBJECT DriverObject
;
1420 PMODULE_OBJECT ModuleObject
;
1424 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1427 * Get the service name from the registry key name
1430 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1432 Start
= DriverServiceName
->Buffer
;
1436 RtlInitUnicodeString(&ServiceName
, Start
);
1439 * Construct the driver object name
1442 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1443 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1444 ObjectName
.Buffer
= ExAllocatePool(NonPagedPool
, ObjectName
.MaximumLength
);
1445 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1446 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1447 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1450 * Find the driver object
1453 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1454 KernelMode
, 0, (PVOID
*)&DriverObject
);
1456 if (!NT_SUCCESS(Status
))
1458 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1463 * Free the buffer for driver object name
1466 ExFreePool(ObjectName
.Buffer
);
1469 * Get path of service...
1472 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1474 RtlInitUnicodeString(&ImagePath
, NULL
);
1476 QueryTable
[0].Name
= L
"ImagePath";
1477 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1478 QueryTable
[0].EntryContext
= &ImagePath
;
1480 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1481 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1483 if (!NT_SUCCESS(Status
))
1485 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1490 * Normalize the image path for all later processing.
1493 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1495 if (!NT_SUCCESS(Status
))
1497 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1502 * ... and check if it's loaded
1505 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1506 if (ModuleObject
== NULL
)
1508 return STATUS_UNSUCCESSFUL
;
1512 * Free the service path
1515 RtlFreeUnicodeString(&ImagePath
);
1518 * Unload the module and release the references to the device object
1521 if (DriverObject
->DriverUnload
)
1522 (*DriverObject
->DriverUnload
)(DriverObject
);
1523 ObDereferenceObject(DriverObject
);
1524 ObDereferenceObject(DriverObject
);
1525 LdrUnloadModule(ModuleObject
);
1527 return STATUS_SUCCESS
;
1531 IopMarkLastReinitializeDriver(VOID
)
1535 KeAcquireSpinLock(&DriverReinitListLock
,
1538 if (IsListEmpty(&DriverReinitListHead
))
1540 DriverReinitTailEntry
= NULL
;
1544 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1547 KeReleaseSpinLock(&DriverReinitListLock
,
1553 IopReinitializeDrivers(VOID
)
1555 PDRIVER_REINIT_ITEM ReinitItem
;
1559 KeAcquireSpinLock(&DriverReinitListLock
,
1562 if (DriverReinitTailEntry
== NULL
)
1564 KeReleaseSpinLock(&DriverReinitListLock
,
1569 KeReleaseSpinLock(&DriverReinitListLock
,
1574 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1575 &DriverReinitListLock
);
1579 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1581 /* Increment reinitialization counter */
1582 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1584 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1585 ReinitItem
->Context
,
1586 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1590 if (Entry
== DriverReinitTailEntry
)
1595 /* PUBLIC FUNCTIONS ***********************************************************/
1604 IN PUNICODE_STRING DriverName
, OPTIONAL
1605 IN PDRIVER_INITIALIZE InitializationFunction
1608 WCHAR NameBuffer
[100];
1610 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1612 OBJECT_ATTRIBUTES ObjectAttributes
;
1614 PDRIVER_OBJECT DriverObject
;
1615 UNICODE_STRING ServiceKeyName
;
1618 /* First, create a unique name for the driver if we don't have one */
1621 /* Create a random name and set up the string*/
1622 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1623 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1624 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1625 LocalDriverName
.Buffer
= NameBuffer
;
1629 /* So we can avoid another code path, use a local var */
1630 LocalDriverName
= *DriverName
;
1633 /* Initialize the Attributes */
1634 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1635 InitializeObjectAttributes(&ObjectAttributes
,
1637 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1641 /* Create the Object */
1642 Status
= ObCreateObject(KernelMode
,
1650 (PVOID
*)&DriverObject
);
1652 /* Return on failure */
1653 if (!NT_SUCCESS(Status
)) return Status
;
1655 /* Set up the Object */
1656 RtlZeroMemory(DriverObject
, ObjectSize
);
1657 DriverObject
->Type
= IO_TYPE_DRIVER
;
1658 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1659 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1660 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1661 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1662 DriverObject
->DriverInit
= InitializationFunction
;
1663 /* FIXME: Invalidate all Major Functions b/c now they are NULL and might crash */
1665 /* Set up the Service Key Name */
1666 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1667 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1668 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1669 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1670 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1671 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1673 /* Also store it in the Driver Object. This is a bit of a hack. */
1674 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1676 /* Add the Object and get its handle */
1677 Status
= ObInsertObject(DriverObject
,
1684 /* Return on Failure */
1685 if (!NT_SUCCESS(Status
)) return Status
;
1687 /* Now reference it */
1688 Status
= ObReferenceObjectByHandle(hDriver
,
1692 (PVOID
*)&DriverObject
,
1696 /* Finally, call its init function */
1697 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1699 if (!NT_SUCCESS(Status
)) {
1700 /* If it didn't work, then kill the object */
1701 ObMakeTemporaryObject(DriverObject
);
1702 ObDereferenceObject(DriverObject
);
1705 /* Return the Status */
1715 IN PDRIVER_OBJECT DriverObject
1718 /* Simply derefence the Object */
1719 ObDereferenceObject(DriverObject
);
1726 * Loads a device driver.
1730 * Name of the service to load (registry key).
1740 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1742 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1743 UNICODE_STRING ImagePath
;
1744 UNICODE_STRING ServiceName
;
1747 PDEVICE_NODE DeviceNode
;
1748 PMODULE_OBJECT ModuleObject
;
1749 PDRIVER_OBJECT DriverObject
;
1752 DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName
);
1755 * Check security privileges
1758 /* FIXME: Uncomment when privileges will be correctly implemented. */
1760 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, KeGetPreviousMode()))
1762 DPRINT("Privilege not held\n");
1763 return STATUS_PRIVILEGE_NOT_HELD
;
1767 RtlInitUnicodeString(&ImagePath
, NULL
);
1770 * Get the service name from the registry key name.
1773 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1775 Start
= DriverServiceName
->Buffer
;
1779 RtlInitUnicodeString(&ServiceName
, Start
);
1785 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1787 RtlInitUnicodeString(&ImagePath
, NULL
);
1789 QueryTable
[0].Name
= L
"Type";
1790 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1791 QueryTable
[0].EntryContext
= &Type
;
1793 QueryTable
[1].Name
= L
"ImagePath";
1794 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1795 QueryTable
[1].EntryContext
= &ImagePath
;
1797 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1798 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1800 if (!NT_SUCCESS(Status
))
1802 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1803 RtlFreeUnicodeString(&ImagePath
);
1808 * Normalize the image path for all later processing.
1811 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1813 if (!NT_SUCCESS(Status
))
1815 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1819 DPRINT("FullImagePath: '%S'\n", ImagePath
.Buffer
);
1820 DPRINT("Type: %lx\n", Type
);
1823 * See, if the driver module isn't already loaded
1826 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1827 if (ModuleObject
!= NULL
)
1829 DPRINT("Image already loaded\n");
1830 return STATUS_IMAGE_ALREADY_LOADED
;
1834 * Create device node
1837 /* Use IopRootDeviceNode for now */
1838 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1840 if (!NT_SUCCESS(Status
))
1842 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1847 * Load the driver module
1850 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1852 if (!NT_SUCCESS(Status
))
1854 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1855 IopFreeDeviceNode(DeviceNode
);
1860 * Set a service name for the device node
1863 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1865 Start
= DriverServiceName
->Buffer
;
1868 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, Start
);
1871 * Initialize the driver module
1874 Status
= IopInitializeDriverModule(
1877 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1878 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1881 if (!NT_SUCCESS(Status
))
1883 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1884 LdrUnloadModule(ModuleObject
);
1885 IopFreeDeviceNode(DeviceNode
);
1889 IopInitializeDevice(DeviceNode
, DriverObject
);
1897 * Unloads a legacy device driver.
1901 * Name of the service to unload (registry key).
1911 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1913 return IopUnloadDriver(DriverServiceName
, FALSE
);
1917 * IoRegisterDriverReinitialization
1924 IoRegisterDriverReinitialization(
1925 PDRIVER_OBJECT DriverObject
,
1926 PDRIVER_REINITIALIZE ReinitRoutine
,
1929 PDRIVER_REINIT_ITEM ReinitItem
;
1931 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
1932 if (ReinitItem
== NULL
)
1935 ReinitItem
->DriverObject
= DriverObject
;
1936 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1937 ReinitItem
->Context
= Context
;
1939 ExInterlockedInsertTailList(
1940 &DriverReinitListHead
,
1941 &ReinitItem
->ItemEntry
,
1942 &DriverReinitListLock
);
1946 * IoAllocateDriverObjectExtension
1953 IoAllocateDriverObjectExtension(
1954 PDRIVER_OBJECT DriverObject
,
1955 PVOID ClientIdentificationAddress
,
1956 ULONG DriverObjectExtensionSize
,
1957 PVOID
*DriverObjectExtension
)
1960 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
1961 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
1963 NewDriverExtension
= ExAllocatePoolWithTag(
1965 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
1966 DriverObjectExtensionSize
,
1967 TAG_DRIVER_EXTENSION
);
1969 if (NewDriverExtension
== NULL
)
1971 return STATUS_INSUFFICIENT_RESOURCES
;
1974 OldIrql
= KeRaiseIrqlToDpcLevel();
1976 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
1977 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1979 for (DriverExtensions
= DriverObject
->DriverSection
;
1980 DriverExtensions
!= NULL
;
1981 DriverExtensions
= DriverExtensions
->Link
)
1983 if (DriverExtensions
->ClientIdentificationAddress
==
1984 ClientIdentificationAddress
)
1986 KfLowerIrql(OldIrql
);
1987 return STATUS_OBJECT_NAME_COLLISION
;
1991 DriverObject
->DriverSection
= NewDriverExtension
;
1993 KfLowerIrql(OldIrql
);
1995 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
1997 return STATUS_SUCCESS
;
2001 * IoGetDriverObjectExtension
2008 IoGetDriverObjectExtension(
2009 PDRIVER_OBJECT DriverObject
,
2010 PVOID ClientIdentificationAddress
)
2013 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2015 OldIrql
= KeRaiseIrqlToDpcLevel();
2017 for (DriverExtensions
= DriverObject
->DriverSection
;
2018 DriverExtensions
!= NULL
&&
2019 DriverExtensions
->ClientIdentificationAddress
!=
2020 ClientIdentificationAddress
;
2021 DriverExtensions
= DriverExtensions
->Link
)
2024 KfLowerIrql(OldIrql
);
2026 if (DriverExtensions
== NULL
)
2029 return &DriverExtensions
->Extension
;