2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/driver.c
5 * PURPOSE: Loading and unloading of drivers
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Filip Navara (xnavara@volny.cz)
11 /* INCLUDES *******************************************************************/
15 #include <internal/debug.h>
18 extern LOADER_PARAMETER_BLOCK KeLoaderBlock
;
19 extern ULONG KeTickCount
;
20 extern BOOLEAN SetupMode
;
23 LdrProcessModule(PVOID ModuleLoadBase
,
24 PUNICODE_STRING ModuleName
,
25 PLDR_DATA_TABLE_ENTRY
*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 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
76 POBJECT_TYPE IoDriverObjectType
= NULL
;
78 /* DECLARATIONS ***************************************************************/
81 IopDeleteDriver(PVOID ObjectBody
);
83 /* PRIVATE FUNCTIONS **********************************************************/
87 IopInitDriverImplementation(VOID
)
89 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
92 DPRINT("Creating Registry Object Type\n");
94 /* Initialize the Driver object type */
95 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
96 RtlInitUnicodeString(&Name
, L
"Driver");
97 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
98 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DRIVER_OBJECT
);
99 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
100 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
101 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDriver
;
103 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoDriverObjectType
);
105 InitializeListHead(&DriverReinitListHead
);
106 KeInitializeSpinLock(&DriverReinitListLock
);
107 DriverReinitTailEntry
= NULL
;
109 InitializeListHead(&DriverBootReinitListHead
);
110 KeInitializeSpinLock(&DriverBootReinitListLock
);
111 DriverBootReinitTailEntry
= NULL
;
115 IopInvalidDeviceRequest(
116 PDEVICE_OBJECT DeviceObject
,
119 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
120 Irp
->IoStatus
.Information
= 0;
121 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
122 return STATUS_INVALID_DEVICE_REQUEST
;
126 IopDeleteDriver(PVOID ObjectBody
)
128 PDRIVER_OBJECT Object
= ObjectBody
;
130 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
132 DPRINT("IopDeleteDriver(ObjectBody 0x%p)\n", ObjectBody
);
134 ExFreePool(Object
->DriverExtension
);
135 ExFreePool(Object
->DriverName
.Buffer
);
137 OldIrql
= KeRaiseIrqlToDpcLevel();
139 for (DriverExtension
= Object
->DriverSection
;
140 DriverExtension
!= NULL
;
141 DriverExtension
= NextDriverExtension
)
143 NextDriverExtension
= DriverExtension
->Link
;
144 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
147 KfLowerIrql(OldIrql
);
152 PDRIVER_OBJECT
*DriverObject
,
153 PUNICODE_STRING ServiceName
,
156 PDRIVER_OBJECT Object
;
157 WCHAR NameBuffer
[MAX_PATH
];
158 UNICODE_STRING DriverName
;
159 OBJECT_ATTRIBUTES ObjectAttributes
;
162 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
163 DriverObject
, ServiceName
, FileSystem
);
165 *DriverObject
= NULL
;
167 /* Create ModuleName string */
168 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
169 /* We don't know which DriverObject we have to open */
170 return STATUS_INVALID_PARAMETER_2
;
172 DriverName
.Buffer
= NameBuffer
;
173 DriverName
.Length
= 0;
174 DriverName
.MaximumLength
= sizeof(NameBuffer
);
176 if (FileSystem
== TRUE
)
177 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
179 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
180 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
182 DPRINT("Driver name: '%wZ'\n", &DriverName
);
184 /* Initialize ObjectAttributes for driver object */
185 InitializeObjectAttributes(
188 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
192 /* Open driver object */
193 Status
= ObReferenceObjectByName(
196 NULL
, /* PassedAccessState */
197 0, /* DesiredAccess */
200 NULL
, /* ParseContext */
203 if (!NT_SUCCESS(Status
))
206 *DriverObject
= Object
;
208 return STATUS_SUCCESS
;
212 IopCreateDriverObject(
213 PDRIVER_OBJECT
*DriverObject
,
214 PUNICODE_STRING ServiceName
,
215 ULONG CreateAttributes
,
217 PVOID DriverImageStart
,
218 ULONG DriverImageSize
)
220 PDRIVER_OBJECT Object
;
221 WCHAR NameBuffer
[MAX_PATH
];
222 UNICODE_STRING DriverName
;
223 OBJECT_ATTRIBUTES ObjectAttributes
;
228 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
229 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
231 *DriverObject
= NULL
;
233 /* Create ModuleName string */
234 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
236 if (FileSystem
== TRUE
)
237 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
239 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
240 wcscat(NameBuffer
, ServiceName
->Buffer
);
242 RtlInitUnicodeString(&DriverName
, NameBuffer
);
243 DPRINT("Driver name: '%wZ'\n", &DriverName
);
245 Buffer
= (PWSTR
)ExAllocatePool(PagedPool
, DriverName
.Length
+ sizeof(WCHAR
));
246 /* If we don't success, it is not a problem. Our driver
247 * object will not have associated driver name... */
251 RtlInitUnicodeString(&DriverName
, NULL
);
254 /* Initialize ObjectAttributes for driver object */
255 InitializeObjectAttributes(
258 CreateAttributes
| OBJ_PERMANENT
,
262 /* Create driver object */
263 Status
= ObCreateObject(
269 sizeof(DRIVER_OBJECT
),
274 if (!NT_SUCCESS(Status
))
279 Status
= ObInsertObject(Object
,
285 if (!NT_SUCCESS(Status
))
290 /* Create driver extension */
291 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
292 ExAllocatePoolWithTag(
294 sizeof(DRIVER_EXTENSION
),
295 TAG_DRIVER_EXTENSION
);
297 if (Object
->DriverExtension
== NULL
)
299 return STATUS_NO_MEMORY
;
302 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
304 Object
->Type
= IO_TYPE_DRIVER
;
306 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
307 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
309 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
311 Object
->DriverStart
= DriverImageStart
;
312 Object
->DriverSize
= DriverImageSize
;
315 if (!Object
->DriverName
.Buffer
)
317 Object
->DriverName
.Buffer
= Buffer
;
318 Object
->DriverName
.Length
= DriverName
.Length
;
319 Object
->DriverName
.MaximumLength
= DriverName
.Length
+ sizeof(WCHAR
);
320 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
321 Object
->DriverName
.Buffer
[Object
->DriverName
.Length
/ sizeof(WCHAR
)] = L
'\0';
327 *DriverObject
= Object
;
329 return STATUS_SUCCESS
;
333 * IopDisplayLoadingMessage
335 * Display 'Loading XXX...' message.
341 IopDisplayLoadingMessage(PVOID ServiceName
,
344 CHAR TextBuffer
[256];
345 if (SetupMode
) return;
348 sprintf(TextBuffer
, "Loading %S...\n", (PWCHAR
)ServiceName
);
352 sprintf(TextBuffer
, "Loading %s...\n", (PCHAR
)ServiceName
);
354 HalDisplayString(TextBuffer
);
358 * IopNormalizeImagePath
360 * Normalize an image path to contain complete path.
364 * The input path and on exit the result path. ImagePath.Buffer
365 * must be allocated by ExAllocatePool on input. Caller is responsible
366 * for freeing the buffer when it's no longer needed.
369 * Name of the service that ImagePath belongs to.
375 * The input image path isn't freed on error.
379 IopNormalizeImagePath(
380 IN OUT PUNICODE_STRING ImagePath
,
381 IN PUNICODE_STRING ServiceName
)
383 UNICODE_STRING InputImagePath
;
388 sizeof(UNICODE_STRING
));
390 if (InputImagePath
.Length
== 0)
392 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
393 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
394 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
395 if (ImagePath
->Buffer
== NULL
)
396 return STATUS_NO_MEMORY
;
398 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
399 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
400 wcscat(ImagePath
->Buffer
, L
".sys");
402 if (InputImagePath
.Buffer
[0] != L
'\\')
404 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
405 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
406 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
407 if (ImagePath
->Buffer
== NULL
)
408 return STATUS_NO_MEMORY
;
410 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
411 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
412 ExFreePool(InputImagePath
.Buffer
);
415 return STATUS_SUCCESS
;
419 * IopLoadServiceModule
421 * Load a module specified by registry settings for service.
425 * Name of the service to load.
432 IopLoadServiceModule(
433 IN PUNICODE_STRING ServiceName
,
434 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
436 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
438 UNICODE_STRING ServiceImagePath
;
441 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
444 * Get information about the service.
447 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
449 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
451 QueryTable
[0].Name
= L
"Start";
452 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
453 QueryTable
[0].EntryContext
= &ServiceStart
;
455 QueryTable
[1].Name
= L
"ImagePath";
456 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
457 QueryTable
[1].EntryContext
= &ServiceImagePath
;
459 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
460 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
462 if (!NT_SUCCESS(Status
))
464 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
468 //IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
471 * Normalize the image path for all later processing.
474 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
476 if (!NT_SUCCESS(Status
))
478 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
486 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
488 if (*ModuleObject
== NULL
)
490 Status
= STATUS_UNSUCCESSFUL
;
493 * Special case for boot modules that were loaded by boot loader.
496 if (ServiceStart
== 0)
499 CHAR SearchName
[256];
501 PLOADER_MODULE KeLoaderModules
=
502 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
506 * Improve this searching algorithm by using the image name
507 * stored in registry entry ImageName and use the whole path
508 * (requires change in FreeLoader).
511 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
512 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
514 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
515 if (!_stricmp(ModuleName
, SearchName
))
517 DPRINT("Initializing boot module\n");
519 /* Tell, that the module is already loaded */
520 KeLoaderModules
[i
].Reserved
= 1;
522 Status
= LdrProcessModule(
523 (PVOID
)KeLoaderModules
[i
].ModStart
,
527 KDB_SYMBOLFILE_HOOK(SearchName
);
532 if (!NT_SUCCESS(Status
))
533 /* Try to load it. It may just have been installed by PnP manager */
534 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
538 * Case for rest of the drivers (except disabled)
541 else if (ServiceStart
< 4)
543 DPRINT("Loading module\n");
544 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
549 DPRINT("Module already loaded\n");
550 Status
= STATUS_IMAGE_ALREADY_LOADED
;
553 ExFreePool(ServiceImagePath
.Buffer
);
556 * Now check if the module was loaded successfully.
559 if (!NT_SUCCESS(Status
))
561 DPRINT("Module loading failed (Status %x)\n", Status
);
564 DPRINT("Module loading (Status %x)\n", Status
);
570 * IopInitializeDriverModule
572 * Initalize a loaded driver.
576 * Pointer to device node.
579 * Module object representing the driver. It can be retrieve by
580 * IopLoadServiceModule.
583 * Name of the service (as in registry).
586 * Set to TRUE for file system drivers.
589 * On successful return this contains the driver object representing
594 IopInitializeDriverModule(
595 IN PDEVICE_NODE DeviceNode
,
596 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
597 IN PUNICODE_STRING ServiceName
,
598 IN BOOLEAN FileSystemDriver
,
599 OUT PDRIVER_OBJECT
*DriverObject
)
601 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
602 UNICODE_STRING RegistryKey
;
603 PDRIVER_INITIALIZE DriverEntry
;
606 DriverEntry
= ModuleObject
->EntryPoint
;
608 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
610 RegistryKey
.Length
= 0;
611 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
612 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
613 if (RegistryKey
.Buffer
== NULL
)
615 return STATUS_INSUFFICIENT_RESOURCES
;
617 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
618 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
622 RtlInitUnicodeString(&RegistryKey
, NULL
);
625 Status
= IopCreateDriverObject(
630 ModuleObject
->DllBase
,
631 ModuleObject
->SizeOfImage
);
633 if (!NT_SUCCESS(Status
))
635 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
639 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
640 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
642 IopMarkLastReinitializeDriver();
644 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
646 RtlFreeUnicodeString(&RegistryKey
);
648 if (!NT_SUCCESS(Status
))
650 ObMakeTemporaryObject(*DriverObject
);
651 ObDereferenceObject(*DriverObject
);
655 IopReinitializeDrivers();
657 return STATUS_SUCCESS
;
661 * IopAttachFilterDriversCallback
663 * Internal routine used by IopAttachFilterDrivers.
667 IopAttachFilterDriversCallback(
675 PDEVICE_NODE DeviceNode
= Context
;
676 UNICODE_STRING ServiceName
;
678 PLDR_DATA_TABLE_ENTRY ModuleObject
;
679 PDRIVER_OBJECT DriverObject
;
682 for (Filters
= ValueData
;
683 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
685 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
687 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
688 ServiceName
.Buffer
= Filters
;
689 ServiceName
.MaximumLength
=
690 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
692 /* Load and initialize the filter driver */
693 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
694 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
696 if (!NT_SUCCESS(Status
))
699 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
700 FALSE
, &DriverObject
);
701 if (!NT_SUCCESS(Status
))
706 /* get existing DriverObject pointer */
707 Status
= IopGetDriverObject(
711 if (!NT_SUCCESS(Status
))
715 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
716 if (!NT_SUCCESS(Status
))
720 return STATUS_SUCCESS
;
724 * IopAttachFilterDrivers
726 * Load filter drivers for specified device node.
730 * Set to TRUE for loading lower level filters or FALSE for upper
735 IopAttachFilterDrivers(
736 PDEVICE_NODE DeviceNode
,
739 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
741 UNICODE_STRING Class
;
742 WCHAR ClassBuffer
[40];
746 * First load the device filters
749 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
751 QueryTable
[0].Name
= L
"LowerFilters";
753 QueryTable
[0].Name
= L
"UpperFilters";
754 QueryTable
[0].EntryContext
= NULL
;
755 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
756 QueryTable
[1].QueryRoutine
= NULL
;
757 QueryTable
[1].Name
= NULL
;
759 KeyBuffer
= ExAllocatePool(
761 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
762 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
763 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
765 RtlQueryRegistryValues(
766 RTL_REGISTRY_ABSOLUTE
,
773 * Now get the class GUID
777 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
778 Class
.Buffer
= ClassBuffer
;
779 QueryTable
[0].QueryRoutine
= NULL
;
780 QueryTable
[0].Name
= L
"ClassGUID";
781 QueryTable
[0].EntryContext
= &Class
;
782 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
784 Status
= RtlQueryRegistryValues(
785 RTL_REGISTRY_ABSOLUTE
,
791 ExFreePool(KeyBuffer
);
794 * Load the class filter driver
797 if (NT_SUCCESS(Status
))
799 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
801 QueryTable
[0].Name
= L
"LowerFilters";
803 QueryTable
[0].Name
= L
"UpperFilters";
804 QueryTable
[0].EntryContext
= NULL
;
805 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
807 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
808 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
809 wcscat(KeyBuffer
, ClassBuffer
);
811 RtlQueryRegistryValues(
812 RTL_REGISTRY_ABSOLUTE
,
818 ExFreePool(KeyBuffer
);
821 return STATUS_SUCCESS
;
824 static NTSTATUS STDCALL
825 IopGetGroupOrderList(PWSTR ValueName
,
832 PSERVICE_GROUP Group
;
834 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
835 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
837 if (ValueType
== REG_BINARY
&&
839 ValueLength
>= sizeof(DWORD
) &&
840 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
842 Group
= (PSERVICE_GROUP
)Context
;
843 Group
->TagCount
= ((PULONG
)ValueData
)[0];
844 if (Group
->TagCount
> 0)
846 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
848 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
849 if (Group
->TagArray
== NULL
)
852 return STATUS_INSUFFICIENT_RESOURCES
;
854 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
859 return STATUS_UNSUCCESSFUL
;
863 return STATUS_SUCCESS
;
866 static NTSTATUS STDCALL
867 IopCreateGroupListEntry(PWSTR ValueName
,
874 PSERVICE_GROUP Group
;
875 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
879 if (ValueType
== REG_SZ
)
881 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
883 Group
= ExAllocatePool(NonPagedPool
,
884 sizeof(SERVICE_GROUP
));
887 return(STATUS_INSUFFICIENT_RESOURCES
);
890 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
892 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
895 return(STATUS_INSUFFICIENT_RESOURCES
);
898 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
899 QueryTable
[0].Name
= (PWSTR
)ValueData
;
900 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
902 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
907 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
909 InsertTailList(&GroupListHead
,
910 &Group
->GroupListEntry
);
913 return(STATUS_SUCCESS
);
917 static NTSTATUS STDCALL
918 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
920 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
924 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
926 /* Allocate service entry */
927 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
930 DPRINT1("ExAllocatePool() failed\n");
931 return(STATUS_INSUFFICIENT_RESOURCES
);
933 RtlZeroMemory(Service
, sizeof(SERVICE
));
935 /* Get service data */
936 RtlZeroMemory(&QueryTable
,
939 QueryTable
[0].Name
= L
"Start";
940 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
941 QueryTable
[0].EntryContext
= &Service
->Start
;
943 QueryTable
[1].Name
= L
"Type";
944 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
945 QueryTable
[1].EntryContext
= &Service
->Type
;
947 QueryTable
[2].Name
= L
"ErrorControl";
948 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
949 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
951 QueryTable
[3].Name
= L
"Group";
952 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
953 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
955 QueryTable
[4].Name
= L
"ImagePath";
956 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
957 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
959 QueryTable
[5].Name
= L
"Tag";
960 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
961 QueryTable
[5].EntryContext
= &Service
->Tag
;
963 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
968 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
971 * If something goes wrong during RtlQueryRegistryValues
972 * it'll just drop everything on the floor and return,
973 * so you have to check if the buffers were filled.
974 * Luckily we zerofilled the Service.
976 if (Service
->ServiceGroup
.Buffer
)
978 ExFreePool(Service
->ServiceGroup
.Buffer
);
980 if (Service
->ImagePath
.Buffer
)
982 ExFreePool(Service
->ImagePath
.Buffer
);
988 /* Copy service name */
989 Service
->ServiceName
.Length
= ServiceName
->Length
;
990 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
991 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
992 Service
->ServiceName
.MaximumLength
);
993 RtlCopyMemory(Service
->ServiceName
.Buffer
,
995 ServiceName
->Length
);
996 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
998 /* Build registry path */
999 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1000 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
1001 MAX_PATH
* sizeof(WCHAR
));
1002 wcscpy(Service
->RegistryPath
.Buffer
,
1003 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1004 wcscat(Service
->RegistryPath
.Buffer
,
1005 Service
->ServiceName
.Buffer
);
1006 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
1008 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
1009 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
1010 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
1011 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
1012 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1013 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
1015 /* Append service entry */
1016 InsertTailList(&ServiceListHead
,
1017 &Service
->ServiceListEntry
);
1019 return(STATUS_SUCCESS
);
1023 NTSTATUS INIT_FUNCTION
1024 IoCreateDriverList(VOID
)
1026 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1027 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
1028 OBJECT_ATTRIBUTES ObjectAttributes
;
1029 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1030 UNICODE_STRING SubKeyName
;
1035 ULONG KeyInfoLength
= 0;
1036 ULONG ReturnedLength
;
1038 DPRINT("IoCreateDriverList() called\n");
1040 /* Initialize basic variables */
1041 InitializeListHead(&GroupListHead
);
1042 InitializeListHead(&ServiceListHead
);
1044 /* Build group order list */
1045 RtlZeroMemory(&QueryTable
,
1046 sizeof(QueryTable
));
1048 QueryTable
[0].Name
= L
"List";
1049 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1051 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1052 L
"ServiceGroupOrder",
1056 if (!NT_SUCCESS(Status
))
1059 /* Enumerate services and create the service list */
1060 InitializeObjectAttributes(&ObjectAttributes
,
1062 OBJ_CASE_INSENSITIVE
,
1066 Status
= ZwOpenKey(&KeyHandle
,
1067 KEY_ENUMERATE_SUB_KEYS
,
1069 if (!NT_SUCCESS(Status
))
1074 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1075 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1076 if (KeyInfo
== NULL
)
1079 return(STATUS_INSUFFICIENT_RESOURCES
);
1085 Status
= ZwEnumerateKey(KeyHandle
,
1087 KeyBasicInformation
,
1091 if (NT_SUCCESS(Status
))
1093 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1096 SubKeyName
.Length
= KeyInfo
->NameLength
;
1097 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1098 SubKeyName
.Buffer
= KeyInfo
->Name
;
1099 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1101 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1102 IopCreateServiceListEntry(&SubKeyName
);
1106 if (!NT_SUCCESS(Status
))
1112 ExFreePool(KeyInfo
);
1115 DPRINT("IoCreateDriverList() done\n");
1117 return(STATUS_SUCCESS
);
1120 NTSTATUS INIT_FUNCTION
1121 IoDestroyDriverList(VOID
)
1123 PSERVICE_GROUP CurrentGroup
, tmp1
;
1124 PSERVICE CurrentService
, tmp2
;
1126 DPRINT("IoDestroyDriverList() called\n");
1128 /* Destroy group list */
1129 LIST_FOR_EACH_SAFE(CurrentGroup
, tmp1
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1131 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1132 RemoveEntryList(&CurrentGroup
->GroupListEntry
);
1133 if (CurrentGroup
->TagArray
)
1135 ExFreePool(CurrentGroup
->TagArray
);
1137 ExFreePool(CurrentGroup
);
1140 /* Destroy service list */
1141 LIST_FOR_EACH_SAFE(CurrentService
, tmp2
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1143 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1144 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1145 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1146 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1147 RemoveEntryList(&CurrentService
->ServiceListEntry
);
1148 ExFreePool(CurrentService
);
1151 DPRINT("IoDestroyDriverList() done\n");
1153 return(STATUS_SUCCESS
);
1156 VOID STATIC INIT_FUNCTION
1157 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1161 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1163 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1168 * IopInitializeBuiltinDriver
1170 * Initialize a driver that is already loaded in memory.
1173 NTSTATUS FASTCALL INIT_FUNCTION
1174 IopInitializeBuiltinDriver(
1175 PDEVICE_NODE ModuleDeviceNode
,
1176 PVOID ModuleLoadBase
,
1180 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1181 PDEVICE_NODE DeviceNode
;
1182 PDRIVER_OBJECT DriverObject
;
1184 PCHAR FileNameWithoutPath
;
1185 LPWSTR FileExtension
;
1187 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1188 FileName
, ModuleLoadBase
, ModuleLength
);
1191 * Display 'Loading XXX...' message
1193 IopDisplayLoadingMessage(FileName
, FALSE
);
1196 * Determine the right device object
1199 if (ModuleDeviceNode
== NULL
)
1201 /* Use IopRootDeviceNode for now */
1202 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1203 if (!NT_SUCCESS(Status
))
1205 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1210 DeviceNode
= ModuleDeviceNode
;
1214 * Generate filename without path (not needed by freeldr)
1217 FileNameWithoutPath
= strrchr(FileName
, '\\');
1218 if (FileNameWithoutPath
== NULL
)
1220 FileNameWithoutPath
= FileName
;
1227 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1228 FileNameWithoutPath
);
1229 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1231 if (!NT_SUCCESS(Status
))
1233 if (ModuleDeviceNode
== NULL
)
1234 IopFreeDeviceNode(DeviceNode
);
1235 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1240 KDB_SYMBOLFILE_HOOK(FileName
);
1243 * Strip the file extension from ServiceName
1246 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1247 if (FileExtension
!= NULL
)
1249 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1250 FileExtension
[0] = 0;
1254 * Initialize the driver
1257 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1258 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1260 if (!NT_SUCCESS(Status
))
1262 if (ModuleDeviceNode
== NULL
)
1263 IopFreeDeviceNode(DeviceNode
);
1264 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1268 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1269 if (NT_SUCCESS(Status
))
1271 Status
= IopStartDevice(DeviceNode
);
1278 * IopInitializeBootDrivers
1280 * Initialize boot drivers and free memory for boot files.
1290 IopInitializeBootDrivers(VOID
)
1292 ULONG BootDriverCount
;
1298 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1300 UNICODE_STRING DriverName
;
1303 DPRINT("IopInitializeBootDrivers()\n");
1305 BootDriverCount
= 0;
1306 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1308 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1309 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1310 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1311 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1312 Extension
= strrchr(ModuleName
, '.');
1313 if (Extension
== NULL
)
1316 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1318 /* Process symbols for *.exe and *.dll */
1319 KDB_SYMBOLFILE_HOOK(ModuleName
);
1321 /* Log *.exe and *.dll files */
1322 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1323 IopBootLog(&DriverName
, TRUE
);
1324 RtlFreeUnicodeString(&DriverName
);
1326 else if (!_stricmp(Extension
, ".sys"))
1328 /* Initialize and log boot start driver */
1331 Status
= IopInitializeBuiltinDriver(NULL
,
1335 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1336 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1337 RtlFreeUnicodeString(&DriverName
);
1344 * Free memory for all boot files, except ntoskrnl.exe.
1346 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1348 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1349 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1352 KeLoaderBlock
.ModsCount
= 0;
1354 if (BootDriverCount
== 0)
1356 DbgPrint("No boot drivers available.\n");
1357 KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE
);
1361 static INIT_FUNCTION NTSTATUS
1362 IopLoadDriver(PSERVICE Service
)
1364 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1366 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1367 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1368 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1369 if (!NT_SUCCESS(Status
))
1371 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1373 if (Service
->ErrorControl
== 1)
1377 else if (Service
->ErrorControl
== 2)
1379 if (IsLastKnownGood
== FALSE
)
1381 /* Boot last known good configuration */
1384 else if (Service
->ErrorControl
== 3)
1386 if (IsLastKnownGood
== FALSE
)
1388 /* Boot last known good configuration */
1402 * IopInitializeSystemDrivers
1404 * Load drivers marked as system start.
1414 IopInitializeSystemDrivers(VOID
)
1416 PSERVICE_GROUP CurrentGroup
;
1417 PSERVICE CurrentService
;
1421 DPRINT("IopInitializeSystemDrivers()\n");
1423 LIST_FOR_EACH(CurrentGroup
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1425 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1427 /* Load all drivers with a valid tag */
1428 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1430 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1432 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1433 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1434 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1435 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1437 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1438 Status
= IopLoadDriver(CurrentService
);
1443 /* Load all drivers without a tag or with an invalid tag */
1444 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1446 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1447 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1448 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1450 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1452 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1457 if (i
>= CurrentGroup
->TagCount
)
1459 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1460 Status
= IopLoadDriver(CurrentService
);
1467 DPRINT("IopInitializeSystemDrivers() done\n");
1473 * Unloads a device driver.
1477 * Name of the service to unload (registry key).
1480 * Whether to unload Plug & Plug or only legacy drivers. If this
1481 * parameter is set to FALSE, the routine will unload only legacy
1488 * Guard the whole function by SEH.
1492 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1494 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1495 UNICODE_STRING ImagePath
;
1496 UNICODE_STRING ServiceName
;
1497 UNICODE_STRING ObjectName
;
1498 PDRIVER_OBJECT DriverObject
;
1499 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1503 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1508 * Get the service name from the registry key name
1511 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1513 Start
= DriverServiceName
->Buffer
;
1517 RtlInitUnicodeString(&ServiceName
, Start
);
1520 * Construct the driver object name
1523 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1524 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1525 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1526 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1527 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1528 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1531 * Find the driver object
1534 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1535 KernelMode
, 0, (PVOID
*)&DriverObject
);
1537 if (!NT_SUCCESS(Status
))
1539 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1544 * Free the buffer for driver object name
1547 ExFreePool(ObjectName
.Buffer
);
1550 * Get path of service...
1553 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1555 RtlInitUnicodeString(&ImagePath
, NULL
);
1557 QueryTable
[0].Name
= L
"ImagePath";
1558 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1559 QueryTable
[0].EntryContext
= &ImagePath
;
1561 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1562 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1564 if (!NT_SUCCESS(Status
))
1566 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1571 * Normalize the image path for all later processing.
1574 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1576 if (!NT_SUCCESS(Status
))
1578 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1583 * ... and check if it's loaded
1586 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1587 if (ModuleObject
== NULL
)
1589 return STATUS_UNSUCCESSFUL
;
1593 * Free the service path
1596 ExFreePool(ImagePath
.Buffer
);
1599 * Unload the module and release the references to the device object
1602 if (DriverObject
->DriverUnload
)
1603 (*DriverObject
->DriverUnload
)(DriverObject
);
1604 ObDereferenceObject(DriverObject
);
1605 ObDereferenceObject(DriverObject
);
1606 LdrUnloadModule(ModuleObject
);
1608 return STATUS_SUCCESS
;
1612 IopMarkLastReinitializeDriver(VOID
)
1616 KeAcquireSpinLock(&DriverReinitListLock
,
1619 if (IsListEmpty(&DriverReinitListHead
))
1621 DriverReinitTailEntry
= NULL
;
1625 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1628 KeReleaseSpinLock(&DriverReinitListLock
,
1634 IopReinitializeDrivers(VOID
)
1636 PDRIVER_REINIT_ITEM ReinitItem
;
1640 KeAcquireSpinLock(&DriverReinitListLock
,
1643 Entry
= DriverReinitTailEntry
;
1645 KeReleaseSpinLock(&DriverReinitListLock
,
1655 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1656 &DriverReinitListLock
);
1660 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1662 /* Increment reinitialization counter */
1663 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1665 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1666 ReinitItem
->Context
,
1667 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1671 if (Entry
== DriverReinitTailEntry
)
1676 /* PUBLIC FUNCTIONS ***********************************************************/
1685 IN PUNICODE_STRING DriverName
, OPTIONAL
1686 IN PDRIVER_INITIALIZE InitializationFunction
1689 WCHAR NameBuffer
[100];
1691 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1693 OBJECT_ATTRIBUTES ObjectAttributes
;
1695 PDRIVER_OBJECT DriverObject
;
1696 UNICODE_STRING ServiceKeyName
;
1700 /* First, create a unique name for the driver if we don't have one */
1703 /* Create a random name and set up the string*/
1704 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1705 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1706 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1707 LocalDriverName
.Buffer
= NameBuffer
;
1711 /* So we can avoid another code path, use a local var */
1712 LocalDriverName
= *DriverName
;
1715 /* Initialize the Attributes */
1716 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1717 InitializeObjectAttributes(&ObjectAttributes
,
1719 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1723 /* Create the Object */
1724 Status
= ObCreateObject(KernelMode
,
1732 (PVOID
*)&DriverObject
);
1734 /* Return on failure */
1735 if (!NT_SUCCESS(Status
)) return Status
;
1737 /* Set up the Object */
1738 RtlZeroMemory(DriverObject
, ObjectSize
);
1739 DriverObject
->Type
= IO_TYPE_DRIVER
;
1740 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1741 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1742 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1743 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1744 DriverObject
->DriverInit
= InitializationFunction
;
1746 /* Invalidate all Major Functions */
1747 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1749 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1752 /* Set up the Service Key Name */
1753 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1754 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1755 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1756 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1757 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1758 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1760 /* Also store it in the Driver Object. This is a bit of a hack. */
1761 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1763 /* Add the Object and get its handle */
1764 Status
= ObInsertObject(DriverObject
,
1771 /* Return on Failure */
1772 if (!NT_SUCCESS(Status
)) return Status
;
1774 /* Now reference it */
1775 Status
= ObReferenceObjectByHandle(hDriver
,
1779 (PVOID
*)&DriverObject
,
1783 /* Finally, call its init function */
1784 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1786 if (!NT_SUCCESS(Status
)) {
1787 /* If it didn't work, then kill the object */
1788 ObMakeTemporaryObject(DriverObject
);
1789 ObDereferenceObject(DriverObject
);
1792 /* Return the Status */
1802 IN PDRIVER_OBJECT DriverObject
1805 /* Simply derefence the Object */
1806 ObDereferenceObject(DriverObject
);
1813 * Loads a device driver.
1817 * Name of the service to load (registry key).
1827 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1829 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1830 UNICODE_STRING ImagePath
;
1831 UNICODE_STRING ServiceName
;
1832 UNICODE_STRING CapturedDriverServiceName
= {0};
1833 KPROCESSOR_MODE PreviousMode
;
1836 PDEVICE_NODE DeviceNode
;
1837 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1838 PDRIVER_OBJECT DriverObject
;
1843 PreviousMode
= KeGetPreviousMode();
1846 * Check security privileges
1849 /* FIXME: Uncomment when privileges will be correctly implemented. */
1851 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1853 DPRINT("Privilege not held\n");
1854 return STATUS_PRIVILEGE_NOT_HELD
;
1858 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1861 if (!NT_SUCCESS(Status
))
1866 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1868 RtlInitUnicodeString(&ImagePath
, NULL
);
1871 * Get the service name from the registry key name.
1873 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1875 ServiceName
= CapturedDriverServiceName
;
1876 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1877 while (CapturedDriverServiceName
.Buffer
!= cur
)
1881 ServiceName
.Buffer
= cur
+ 1;
1882 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1883 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1884 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1894 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1896 RtlInitUnicodeString(&ImagePath
, NULL
);
1898 QueryTable
[0].Name
= L
"Type";
1899 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1900 QueryTable
[0].EntryContext
= &Type
;
1902 QueryTable
[1].Name
= L
"ImagePath";
1903 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1904 QueryTable
[1].EntryContext
= &ImagePath
;
1906 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1907 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1909 if (!NT_SUCCESS(Status
))
1911 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1912 ExFreePool(ImagePath
.Buffer
);
1913 goto ReleaseCapturedString
;
1917 * Normalize the image path for all later processing.
1920 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1922 if (!NT_SUCCESS(Status
))
1924 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1925 goto ReleaseCapturedString
;
1928 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1929 DPRINT("Type: %lx\n", Type
);
1932 * See, if the driver module isn't already loaded
1935 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1936 if (ModuleObject
!= NULL
)
1938 DPRINT("Image already loaded\n");
1939 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1940 goto ReleaseCapturedString
;
1944 * Create device node
1947 /* Use IopRootDeviceNode for now */
1948 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1950 if (!NT_SUCCESS(Status
))
1952 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1953 goto ReleaseCapturedString
;
1957 * Load the driver module
1960 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1962 if (!NT_SUCCESS(Status
))
1964 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1965 IopFreeDeviceNode(DeviceNode
);
1966 goto ReleaseCapturedString
;
1970 * Set a service name for the device node
1973 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1976 * Initialize the driver module
1979 Status
= IopInitializeDriverModule(
1982 &DeviceNode
->ServiceName
,
1983 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1984 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1987 if (!NT_SUCCESS(Status
))
1989 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1990 LdrUnloadModule(ModuleObject
);
1991 IopFreeDeviceNode(DeviceNode
);
1992 goto ReleaseCapturedString
;
1995 IopInitializeDevice(DeviceNode
, DriverObject
);
1996 Status
= IopStartDevice(DeviceNode
);
1998 ReleaseCapturedString
:
1999 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2008 * Unloads a legacy device driver.
2012 * Name of the service to unload (registry key).
2022 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2024 return IopUnloadDriver(DriverServiceName
, FALSE
);
2028 * IoRegisterDriverReinitialization
2035 IoRegisterDriverReinitialization(
2036 PDRIVER_OBJECT DriverObject
,
2037 PDRIVER_REINITIALIZE ReinitRoutine
,
2040 PDRIVER_REINIT_ITEM ReinitItem
;
2042 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2043 if (ReinitItem
== NULL
)
2046 ReinitItem
->DriverObject
= DriverObject
;
2047 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2048 ReinitItem
->Context
= Context
;
2050 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2052 ExInterlockedInsertTailList(
2053 &DriverReinitListHead
,
2054 &ReinitItem
->ItemEntry
,
2055 &DriverReinitListLock
);
2063 IoRegisterBootDriverReinitialization(
2064 IN PDRIVER_OBJECT DriverObject
,
2065 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2069 PDRIVER_REINIT_ITEM ReinitItem
;
2071 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2072 if (ReinitItem
== NULL
)
2075 ReinitItem
->DriverObject
= DriverObject
;
2076 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2077 ReinitItem
->Context
= Context
;
2079 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2081 ExInterlockedInsertTailList(
2082 &DriverBootReinitListHead
,
2083 &ReinitItem
->ItemEntry
,
2084 &DriverReinitListLock
);
2088 * IoAllocateDriverObjectExtension
2095 IoAllocateDriverObjectExtension(
2096 PDRIVER_OBJECT DriverObject
,
2097 PVOID ClientIdentificationAddress
,
2098 ULONG DriverObjectExtensionSize
,
2099 PVOID
*DriverObjectExtension
)
2102 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2103 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2105 NewDriverExtension
= ExAllocatePoolWithTag(
2107 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2108 DriverObjectExtensionSize
,
2109 TAG_DRIVER_EXTENSION
);
2111 if (NewDriverExtension
== NULL
)
2113 return STATUS_INSUFFICIENT_RESOURCES
;
2116 OldIrql
= KeRaiseIrqlToDpcLevel();
2118 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2119 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2121 for (DriverExtensions
= DriverObject
->DriverSection
;
2122 DriverExtensions
!= NULL
;
2123 DriverExtensions
= DriverExtensions
->Link
)
2125 if (DriverExtensions
->ClientIdentificationAddress
==
2126 ClientIdentificationAddress
)
2128 KfLowerIrql(OldIrql
);
2129 return STATUS_OBJECT_NAME_COLLISION
;
2133 DriverObject
->DriverSection
= NewDriverExtension
;
2135 KfLowerIrql(OldIrql
);
2137 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2139 return STATUS_SUCCESS
;
2143 * IoGetDriverObjectExtension
2150 IoGetDriverObjectExtension(
2151 PDRIVER_OBJECT DriverObject
,
2152 PVOID ClientIdentificationAddress
)
2155 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2157 OldIrql
= KeRaiseIrqlToDpcLevel();
2159 for (DriverExtensions
= DriverObject
->DriverSection
;
2160 DriverExtensions
!= NULL
&&
2161 DriverExtensions
->ClientIdentificationAddress
!=
2162 ClientIdentificationAddress
;
2163 DriverExtensions
= DriverExtensions
->Link
)
2166 KfLowerIrql(OldIrql
);
2168 if (DriverExtensions
== NULL
)
2171 return &DriverExtensions
->Extension
;