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
;
21 extern BOOLEAN NoGuiBoot
;
23 typedef struct _SERVICE_GROUP
25 LIST_ENTRY GroupListEntry
;
26 UNICODE_STRING GroupName
;
27 BOOLEAN ServicesRunning
;
30 } SERVICE_GROUP
, *PSERVICE_GROUP
;
32 typedef struct _SERVICE
34 LIST_ENTRY ServiceListEntry
;
35 UNICODE_STRING ServiceName
;
36 UNICODE_STRING RegistryPath
;
37 UNICODE_STRING ServiceGroup
;
38 UNICODE_STRING ImagePath
;
45 /* BOOLEAN ServiceRunning;*/ // needed ??
48 typedef struct _DRIVER_REINIT_ITEM
51 PDRIVER_OBJECT DriverObject
;
52 PDRIVER_REINITIALIZE ReinitRoutine
;
54 } DRIVER_REINIT_ITEM
, *PDRIVER_REINIT_ITEM
;
56 /* GLOBALS ********************************************************************/
58 static LIST_ENTRY DriverReinitListHead
;
59 static KSPIN_LOCK DriverReinitListLock
;
60 static PLIST_ENTRY DriverReinitTailEntry
;
62 static PLIST_ENTRY DriverBootReinitTailEntry
;
63 static LIST_ENTRY DriverBootReinitListHead
;
64 static KSPIN_LOCK DriverBootReinitListLock
;
66 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
67 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
69 static UNICODE_STRING IopHardwareDatabaseKey
=
70 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
72 POBJECT_TYPE IoDriverObjectType
= NULL
;
74 /* DECLARATIONS ***************************************************************/
77 IopDeleteDriver(PVOID ObjectBody
);
80 LdrProcessModule(PVOID ModuleLoadBase
,
81 PUNICODE_STRING ModuleName
,
82 PLDR_DATA_TABLE_ENTRY
*ModuleObject
);
87 IopDisplayLoadingMessage(PVOID ServiceName
,
90 static VOID INIT_FUNCTION
91 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
);
93 NTSTATUS FASTCALL INIT_FUNCTION
94 IopInitializeBuiltinDriver(
95 PDEVICE_NODE ModuleDeviceNode
,
100 static INIT_FUNCTION NTSTATUS
101 IopLoadDriver(PSERVICE Service
);
103 #if defined (ALLOC_PRAGMA)
104 #pragma alloc_text(INIT, IopInitDriverImplementation)
105 #pragma alloc_text(INIT, IopDisplayLoadingMessage)
106 #pragma alloc_text(INIT, IoCreateDriverList)
107 #pragma alloc_text(INIT, IoDestroyDriverList)
108 #pragma alloc_text(INIT, MiFreeBootDriverMemory)
109 #pragma alloc_text(INIT, IopInitializeBuiltinDriver)
110 #pragma alloc_text(INIT, IopLoadDriver)
114 /* PRIVATE FUNCTIONS **********************************************************/
118 IopInitDriverImplementation(VOID
)
120 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
123 DPRINT("Creating Registry Object Type\n");
125 /* Initialize the Driver object type */
126 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
127 RtlInitUnicodeString(&Name
, L
"Driver");
128 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
129 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DRIVER_OBJECT
);
130 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
131 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
132 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDriver
;
134 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoDriverObjectType
);
136 InitializeListHead(&DriverReinitListHead
);
137 KeInitializeSpinLock(&DriverReinitListLock
);
138 DriverReinitTailEntry
= NULL
;
140 InitializeListHead(&DriverBootReinitListHead
);
141 KeInitializeSpinLock(&DriverBootReinitListLock
);
142 DriverBootReinitTailEntry
= NULL
;
146 IopInvalidDeviceRequest(
147 PDEVICE_OBJECT DeviceObject
,
150 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
151 Irp
->IoStatus
.Information
= 0;
152 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
153 return STATUS_INVALID_DEVICE_REQUEST
;
157 IopDeleteDriver(PVOID ObjectBody
)
159 PDRIVER_OBJECT Object
= ObjectBody
;
161 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
163 DPRINT("IopDeleteDriver(ObjectBody 0x%p)\n", ObjectBody
);
165 ExFreePool(Object
->DriverExtension
);
166 ExFreePool(Object
->DriverName
.Buffer
);
168 OldIrql
= KeRaiseIrqlToDpcLevel();
170 for (DriverExtension
= Object
->DriverSection
;
171 DriverExtension
!= NULL
;
172 DriverExtension
= NextDriverExtension
)
174 NextDriverExtension
= DriverExtension
->Link
;
175 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
178 KfLowerIrql(OldIrql
);
183 PDRIVER_OBJECT
*DriverObject
,
184 PUNICODE_STRING ServiceName
,
187 PDRIVER_OBJECT Object
;
188 WCHAR NameBuffer
[MAX_PATH
];
189 UNICODE_STRING DriverName
;
190 OBJECT_ATTRIBUTES ObjectAttributes
;
193 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
194 DriverObject
, ServiceName
, FileSystem
);
196 *DriverObject
= NULL
;
198 /* Create ModuleName string */
199 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
200 /* We don't know which DriverObject we have to open */
201 return STATUS_INVALID_PARAMETER_2
;
203 DriverName
.Buffer
= NameBuffer
;
204 DriverName
.Length
= 0;
205 DriverName
.MaximumLength
= sizeof(NameBuffer
);
207 if (FileSystem
== TRUE
)
208 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
210 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
211 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
213 DPRINT("Driver name: '%wZ'\n", &DriverName
);
215 /* Initialize ObjectAttributes for driver object */
216 InitializeObjectAttributes(
219 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
223 /* Open driver object */
224 Status
= ObReferenceObjectByName(
227 NULL
, /* PassedAccessState */
228 0, /* DesiredAccess */
231 NULL
, /* ParseContext */
234 if (!NT_SUCCESS(Status
))
237 *DriverObject
= Object
;
239 return STATUS_SUCCESS
;
243 IopCreateDriverObject(
244 PDRIVER_OBJECT
*DriverObject
,
245 PUNICODE_STRING ServiceName
,
246 ULONG CreateAttributes
,
248 PVOID DriverImageStart
,
249 ULONG DriverImageSize
)
251 PDRIVER_OBJECT Object
;
252 WCHAR NameBuffer
[MAX_PATH
];
253 UNICODE_STRING DriverName
;
254 OBJECT_ATTRIBUTES ObjectAttributes
;
259 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
260 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
262 *DriverObject
= NULL
;
264 /* Create ModuleName string */
265 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
267 if (FileSystem
== TRUE
)
268 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
270 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
271 wcscat(NameBuffer
, ServiceName
->Buffer
);
273 RtlInitUnicodeString(&DriverName
, NameBuffer
);
274 DPRINT("Driver name: '%wZ'\n", &DriverName
);
276 Buffer
= (PWSTR
)ExAllocatePool(PagedPool
, DriverName
.Length
+ sizeof(WCHAR
));
277 /* If we don't success, it is not a problem. Our driver
278 * object will not have associated driver name... */
282 RtlInitUnicodeString(&DriverName
, NULL
);
285 /* Initialize ObjectAttributes for driver object */
286 InitializeObjectAttributes(
289 CreateAttributes
| OBJ_PERMANENT
,
293 /* Create driver object */
294 Status
= ObCreateObject(
300 sizeof(DRIVER_OBJECT
),
305 if (!NT_SUCCESS(Status
))
310 Status
= ObInsertObject(Object
,
316 if (!NT_SUCCESS(Status
))
321 /* Create driver extension */
322 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
323 ExAllocatePoolWithTag(
325 sizeof(DRIVER_EXTENSION
),
326 TAG_DRIVER_EXTENSION
);
328 if (Object
->DriverExtension
== NULL
)
330 return STATUS_NO_MEMORY
;
333 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
335 Object
->Type
= IO_TYPE_DRIVER
;
337 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
338 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
340 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
342 Object
->DriverStart
= DriverImageStart
;
343 Object
->DriverSize
= DriverImageSize
;
346 if (!Object
->DriverName
.Buffer
)
348 Object
->DriverName
.Buffer
= Buffer
;
349 Object
->DriverName
.Length
= DriverName
.Length
;
350 Object
->DriverName
.MaximumLength
= DriverName
.Length
+ sizeof(WCHAR
);
351 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
352 Object
->DriverName
.Buffer
[Object
->DriverName
.Length
/ sizeof(WCHAR
)] = L
'\0';
358 *DriverObject
= Object
;
360 return STATUS_SUCCESS
;
364 * IopDisplayLoadingMessage
366 * Display 'Loading XXX...' message.
372 IopDisplayLoadingMessage(PVOID ServiceName
,
375 CHAR TextBuffer
[256];
376 if (SetupMode
|| !NoGuiBoot
) return;
379 sprintf(TextBuffer
, "Loading %S...\n", (PWCHAR
)ServiceName
);
383 sprintf(TextBuffer
, "Loading %s...\n", (PCHAR
)ServiceName
);
385 HalDisplayString(TextBuffer
);
389 * IopNormalizeImagePath
391 * Normalize an image path to contain complete path.
395 * The input path and on exit the result path. ImagePath.Buffer
396 * must be allocated by ExAllocatePool on input. Caller is responsible
397 * for freeing the buffer when it's no longer needed.
400 * Name of the service that ImagePath belongs to.
406 * The input image path isn't freed on error.
410 IopNormalizeImagePath(
411 IN OUT PUNICODE_STRING ImagePath
,
412 IN PUNICODE_STRING ServiceName
)
414 UNICODE_STRING InputImagePath
;
419 sizeof(UNICODE_STRING
));
421 if (InputImagePath
.Length
== 0)
423 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
424 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
425 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
426 if (ImagePath
->Buffer
== NULL
)
427 return STATUS_NO_MEMORY
;
429 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
430 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
431 wcscat(ImagePath
->Buffer
, L
".sys");
433 if (InputImagePath
.Buffer
[0] != L
'\\')
435 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
436 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
437 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
438 if (ImagePath
->Buffer
== NULL
)
439 return STATUS_NO_MEMORY
;
441 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
442 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
443 ExFreePool(InputImagePath
.Buffer
);
446 return STATUS_SUCCESS
;
450 * IopLoadServiceModule
452 * Load a module specified by registry settings for service.
456 * Name of the service to load.
463 IopLoadServiceModule(
464 IN PUNICODE_STRING ServiceName
,
465 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
467 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
469 UNICODE_STRING ServiceImagePath
;
472 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
475 * Get information about the service.
478 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
480 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
482 QueryTable
[0].Name
= L
"Start";
483 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
484 QueryTable
[0].EntryContext
= &ServiceStart
;
486 QueryTable
[1].Name
= L
"ImagePath";
487 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
488 QueryTable
[1].EntryContext
= &ServiceImagePath
;
490 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
491 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
493 if (!NT_SUCCESS(Status
))
495 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
499 //IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
502 * Normalize the image path for all later processing.
505 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
507 if (!NT_SUCCESS(Status
))
509 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
517 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
519 if (*ModuleObject
== NULL
)
521 Status
= STATUS_UNSUCCESSFUL
;
524 * Special case for boot modules that were loaded by boot loader.
527 if (ServiceStart
== 0)
530 CHAR SearchName
[256];
532 PLOADER_MODULE KeLoaderModules
=
533 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
537 * Improve this searching algorithm by using the image name
538 * stored in registry entry ImageName and use the whole path
539 * (requires change in FreeLoader).
542 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
543 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
545 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
546 if (!_stricmp(ModuleName
, SearchName
))
548 DPRINT("Initializing boot module\n");
550 /* Tell, that the module is already loaded */
551 KeLoaderModules
[i
].Reserved
= 1;
553 Status
= LdrProcessModule(
554 (PVOID
)KeLoaderModules
[i
].ModStart
,
558 KDB_SYMBOLFILE_HOOK(SearchName
);
563 if (!NT_SUCCESS(Status
))
564 /* Try to load it. It may just have been installed by PnP manager */
565 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
569 * Case for rest of the drivers (except disabled)
572 else if (ServiceStart
< 4)
574 DPRINT("Loading module\n");
575 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
580 DPRINT("Module already loaded\n");
581 Status
= STATUS_IMAGE_ALREADY_LOADED
;
584 ExFreePool(ServiceImagePath
.Buffer
);
587 * Now check if the module was loaded successfully.
590 if (!NT_SUCCESS(Status
))
592 DPRINT("Module loading failed (Status %x)\n", Status
);
595 DPRINT("Module loading (Status %x)\n", Status
);
601 * IopInitializeDriverModule
603 * Initalize a loaded driver.
607 * Pointer to device node.
610 * Module object representing the driver. It can be retrieve by
611 * IopLoadServiceModule.
614 * Name of the service (as in registry).
617 * Set to TRUE for file system drivers.
620 * On successful return this contains the driver object representing
625 IopInitializeDriverModule(
626 IN PDEVICE_NODE DeviceNode
,
627 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
628 IN PUNICODE_STRING ServiceName
,
629 IN BOOLEAN FileSystemDriver
,
630 OUT PDRIVER_OBJECT
*DriverObject
)
632 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
633 UNICODE_STRING RegistryKey
;
634 PDRIVER_INITIALIZE DriverEntry
;
637 DriverEntry
= ModuleObject
->EntryPoint
;
639 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
641 RegistryKey
.Length
= 0;
642 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
643 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
644 if (RegistryKey
.Buffer
== NULL
)
646 return STATUS_INSUFFICIENT_RESOURCES
;
648 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
649 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
653 RtlInitUnicodeString(&RegistryKey
, NULL
);
656 Status
= IopCreateDriverObject(
661 ModuleObject
->DllBase
,
662 ModuleObject
->SizeOfImage
);
664 if (!NT_SUCCESS(Status
))
666 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
670 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
671 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
673 IopMarkLastReinitializeDriver();
675 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
677 RtlFreeUnicodeString(&RegistryKey
);
679 if (!NT_SUCCESS(Status
))
681 ObMakeTemporaryObject(*DriverObject
);
682 ObDereferenceObject(*DriverObject
);
686 IopReinitializeDrivers();
688 return STATUS_SUCCESS
;
692 * IopAttachFilterDriversCallback
694 * Internal routine used by IopAttachFilterDrivers.
698 IopAttachFilterDriversCallback(
706 PDEVICE_NODE DeviceNode
= Context
;
707 UNICODE_STRING ServiceName
;
709 PLDR_DATA_TABLE_ENTRY ModuleObject
;
710 PDRIVER_OBJECT DriverObject
;
713 for (Filters
= ValueData
;
714 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
716 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
718 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
719 ServiceName
.Buffer
= Filters
;
720 ServiceName
.MaximumLength
=
721 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
723 /* Load and initialize the filter driver */
724 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
725 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
727 if (!NT_SUCCESS(Status
))
730 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
731 FALSE
, &DriverObject
);
732 if (!NT_SUCCESS(Status
))
737 /* get existing DriverObject pointer */
738 Status
= IopGetDriverObject(
742 if (!NT_SUCCESS(Status
))
746 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
747 if (!NT_SUCCESS(Status
))
751 return STATUS_SUCCESS
;
755 * IopAttachFilterDrivers
757 * Load filter drivers for specified device node.
761 * Set to TRUE for loading lower level filters or FALSE for upper
766 IopAttachFilterDrivers(
767 PDEVICE_NODE DeviceNode
,
770 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
772 UNICODE_STRING Class
;
773 WCHAR ClassBuffer
[40];
777 * First load the device filters
780 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
782 QueryTable
[0].Name
= L
"LowerFilters";
784 QueryTable
[0].Name
= L
"UpperFilters";
785 QueryTable
[0].EntryContext
= NULL
;
786 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
787 QueryTable
[1].QueryRoutine
= NULL
;
788 QueryTable
[1].Name
= NULL
;
790 KeyBuffer
= ExAllocatePool(
792 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
793 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
794 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
796 RtlQueryRegistryValues(
797 RTL_REGISTRY_ABSOLUTE
,
804 * Now get the class GUID
808 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
809 Class
.Buffer
= ClassBuffer
;
810 QueryTable
[0].QueryRoutine
= NULL
;
811 QueryTable
[0].Name
= L
"ClassGUID";
812 QueryTable
[0].EntryContext
= &Class
;
813 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
815 Status
= RtlQueryRegistryValues(
816 RTL_REGISTRY_ABSOLUTE
,
822 ExFreePool(KeyBuffer
);
825 * Load the class filter driver
828 if (NT_SUCCESS(Status
))
830 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
832 QueryTable
[0].Name
= L
"LowerFilters";
834 QueryTable
[0].Name
= L
"UpperFilters";
835 QueryTable
[0].EntryContext
= NULL
;
836 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
838 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
839 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
840 wcscat(KeyBuffer
, ClassBuffer
);
842 RtlQueryRegistryValues(
843 RTL_REGISTRY_ABSOLUTE
,
849 ExFreePool(KeyBuffer
);
852 return STATUS_SUCCESS
;
855 static NTSTATUS STDCALL
856 IopGetGroupOrderList(PWSTR ValueName
,
863 PSERVICE_GROUP Group
;
865 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
866 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
868 if (ValueType
== REG_BINARY
&&
870 ValueLength
>= sizeof(DWORD
) &&
871 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
873 Group
= (PSERVICE_GROUP
)Context
;
874 Group
->TagCount
= ((PULONG
)ValueData
)[0];
875 if (Group
->TagCount
> 0)
877 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
879 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
880 if (Group
->TagArray
== NULL
)
883 return STATUS_INSUFFICIENT_RESOURCES
;
885 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
890 return STATUS_UNSUCCESSFUL
;
894 return STATUS_SUCCESS
;
897 static NTSTATUS STDCALL
898 IopCreateGroupListEntry(PWSTR ValueName
,
905 PSERVICE_GROUP Group
;
906 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
910 if (ValueType
== REG_SZ
)
912 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
914 Group
= ExAllocatePool(NonPagedPool
,
915 sizeof(SERVICE_GROUP
));
918 return(STATUS_INSUFFICIENT_RESOURCES
);
921 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
923 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
926 return(STATUS_INSUFFICIENT_RESOURCES
);
929 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
930 QueryTable
[0].Name
= (PWSTR
)ValueData
;
931 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
933 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
938 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
940 InsertTailList(&GroupListHead
,
941 &Group
->GroupListEntry
);
944 return(STATUS_SUCCESS
);
948 static NTSTATUS STDCALL
949 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
951 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
955 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
957 /* Allocate service entry */
958 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
961 DPRINT1("ExAllocatePool() failed\n");
962 return(STATUS_INSUFFICIENT_RESOURCES
);
964 RtlZeroMemory(Service
, sizeof(SERVICE
));
966 /* Get service data */
967 RtlZeroMemory(&QueryTable
,
970 QueryTable
[0].Name
= L
"Start";
971 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
972 QueryTable
[0].EntryContext
= &Service
->Start
;
974 QueryTable
[1].Name
= L
"Type";
975 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
976 QueryTable
[1].EntryContext
= &Service
->Type
;
978 QueryTable
[2].Name
= L
"ErrorControl";
979 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
980 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
982 QueryTable
[3].Name
= L
"Group";
983 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
984 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
986 QueryTable
[4].Name
= L
"ImagePath";
987 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
988 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
990 QueryTable
[5].Name
= L
"Tag";
991 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
992 QueryTable
[5].EntryContext
= &Service
->Tag
;
994 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
999 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
1002 * If something goes wrong during RtlQueryRegistryValues
1003 * it'll just drop everything on the floor and return,
1004 * so you have to check if the buffers were filled.
1005 * Luckily we zerofilled the Service.
1007 if (Service
->ServiceGroup
.Buffer
)
1009 ExFreePool(Service
->ServiceGroup
.Buffer
);
1011 if (Service
->ImagePath
.Buffer
)
1013 ExFreePool(Service
->ImagePath
.Buffer
);
1015 ExFreePool(Service
);
1019 /* Copy service name */
1020 Service
->ServiceName
.Length
= ServiceName
->Length
;
1021 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
1022 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
1023 Service
->ServiceName
.MaximumLength
);
1024 RtlCopyMemory(Service
->ServiceName
.Buffer
,
1025 ServiceName
->Buffer
,
1026 ServiceName
->Length
);
1027 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
1029 /* Build registry path */
1030 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1031 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
1032 MAX_PATH
* sizeof(WCHAR
));
1033 wcscpy(Service
->RegistryPath
.Buffer
,
1034 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1035 wcscat(Service
->RegistryPath
.Buffer
,
1036 Service
->ServiceName
.Buffer
);
1037 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
1039 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
1040 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
1041 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
1042 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
1043 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1044 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
1046 /* Append service entry */
1047 InsertTailList(&ServiceListHead
,
1048 &Service
->ServiceListEntry
);
1050 return(STATUS_SUCCESS
);
1054 NTSTATUS INIT_FUNCTION
1055 IoCreateDriverList(VOID
)
1057 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1058 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
1059 OBJECT_ATTRIBUTES ObjectAttributes
;
1060 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1061 UNICODE_STRING SubKeyName
;
1066 ULONG KeyInfoLength
= 0;
1067 ULONG ReturnedLength
;
1069 DPRINT("IoCreateDriverList() called\n");
1071 /* Initialize basic variables */
1072 InitializeListHead(&GroupListHead
);
1073 InitializeListHead(&ServiceListHead
);
1075 /* Build group order list */
1076 RtlZeroMemory(&QueryTable
,
1077 sizeof(QueryTable
));
1079 QueryTable
[0].Name
= L
"List";
1080 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1082 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1083 L
"ServiceGroupOrder",
1087 if (!NT_SUCCESS(Status
))
1090 /* Enumerate services and create the service list */
1091 InitializeObjectAttributes(&ObjectAttributes
,
1093 OBJ_CASE_INSENSITIVE
,
1097 Status
= ZwOpenKey(&KeyHandle
,
1098 KEY_ENUMERATE_SUB_KEYS
,
1100 if (!NT_SUCCESS(Status
))
1105 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1106 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1107 if (KeyInfo
== NULL
)
1110 return(STATUS_INSUFFICIENT_RESOURCES
);
1116 Status
= ZwEnumerateKey(KeyHandle
,
1118 KeyBasicInformation
,
1122 if (NT_SUCCESS(Status
))
1124 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1127 SubKeyName
.Length
= KeyInfo
->NameLength
;
1128 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1129 SubKeyName
.Buffer
= KeyInfo
->Name
;
1130 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1132 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1133 IopCreateServiceListEntry(&SubKeyName
);
1137 if (!NT_SUCCESS(Status
))
1143 ExFreePool(KeyInfo
);
1146 DPRINT("IoCreateDriverList() done\n");
1148 return(STATUS_SUCCESS
);
1151 NTSTATUS INIT_FUNCTION
1152 IoDestroyDriverList(VOID
)
1154 PSERVICE_GROUP CurrentGroup
, tmp1
;
1155 PSERVICE CurrentService
, tmp2
;
1157 DPRINT("IoDestroyDriverList() called\n");
1159 /* Destroy group list */
1160 LIST_FOR_EACH_SAFE(CurrentGroup
, tmp1
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1162 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1163 RemoveEntryList(&CurrentGroup
->GroupListEntry
);
1164 if (CurrentGroup
->TagArray
)
1166 ExFreePool(CurrentGroup
->TagArray
);
1168 ExFreePool(CurrentGroup
);
1171 /* Destroy service list */
1172 LIST_FOR_EACH_SAFE(CurrentService
, tmp2
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1174 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1175 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1176 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1177 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1178 RemoveEntryList(&CurrentService
->ServiceListEntry
);
1179 ExFreePool(CurrentService
);
1182 DPRINT("IoDestroyDriverList() done\n");
1184 return(STATUS_SUCCESS
);
1187 static VOID INIT_FUNCTION
1188 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1192 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1194 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1199 * IopInitializeBuiltinDriver
1201 * Initialize a driver that is already loaded in memory.
1204 NTSTATUS FASTCALL INIT_FUNCTION
1205 IopInitializeBuiltinDriver(
1206 PDEVICE_NODE ModuleDeviceNode
,
1207 PVOID ModuleLoadBase
,
1211 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1212 PDEVICE_NODE DeviceNode
;
1213 PDRIVER_OBJECT DriverObject
;
1215 PCHAR FileNameWithoutPath
;
1216 LPWSTR FileExtension
;
1218 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1219 FileName
, ModuleLoadBase
, ModuleLength
);
1222 * Display 'Loading XXX...' message
1224 IopDisplayLoadingMessage(FileName
, FALSE
);
1227 * Determine the right device object
1230 if (ModuleDeviceNode
== NULL
)
1232 /* Use IopRootDeviceNode for now */
1233 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1234 if (!NT_SUCCESS(Status
))
1236 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1241 DeviceNode
= ModuleDeviceNode
;
1245 * Generate filename without path (not needed by freeldr)
1248 FileNameWithoutPath
= strrchr(FileName
, '\\');
1249 if (FileNameWithoutPath
== NULL
)
1251 FileNameWithoutPath
= FileName
;
1258 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1259 FileNameWithoutPath
);
1260 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1262 if (!NT_SUCCESS(Status
))
1264 if (ModuleDeviceNode
== NULL
)
1265 IopFreeDeviceNode(DeviceNode
);
1266 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1271 KDB_SYMBOLFILE_HOOK(FileName
);
1274 * Strip the file extension from ServiceName
1277 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1278 if (FileExtension
!= NULL
)
1280 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1281 FileExtension
[0] = 0;
1285 * Initialize the driver
1288 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1289 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1291 if (!NT_SUCCESS(Status
))
1293 if (ModuleDeviceNode
== NULL
)
1294 IopFreeDeviceNode(DeviceNode
);
1295 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1299 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1300 if (NT_SUCCESS(Status
))
1302 Status
= IopStartDevice(DeviceNode
);
1309 * IopInitializeBootDrivers
1311 * Initialize boot drivers and free memory for boot files.
1321 IopInitializeBootDrivers(VOID
)
1323 ULONG BootDriverCount
;
1329 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1331 UNICODE_STRING DriverName
;
1334 DPRINT("IopInitializeBootDrivers()\n");
1336 BootDriverCount
= 0;
1337 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1339 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1340 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1341 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1342 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1343 Extension
= strrchr(ModuleName
, '.');
1344 if (Extension
== NULL
)
1347 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1349 /* Process symbols for *.exe and *.dll */
1350 KDB_SYMBOLFILE_HOOK(ModuleName
);
1352 /* Log *.exe and *.dll files */
1353 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1354 IopBootLog(&DriverName
, TRUE
);
1355 RtlFreeUnicodeString(&DriverName
);
1357 else if (!_stricmp(Extension
, ".sys"))
1359 /* Initialize and log boot start driver */
1362 Status
= IopInitializeBuiltinDriver(NULL
,
1366 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1367 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1368 RtlFreeUnicodeString(&DriverName
);
1375 * Free memory for all boot files, except ntoskrnl.exe.
1377 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1379 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1380 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1383 KeLoaderBlock
.ModsCount
= 0;
1385 if (BootDriverCount
== 0)
1387 DbgPrint("No boot drivers available.\n");
1388 KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE
);
1392 static INIT_FUNCTION NTSTATUS
1393 IopLoadDriver(PSERVICE Service
)
1395 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1397 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1398 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1399 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1400 if (!NT_SUCCESS(Status
))
1402 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1404 if (Service
->ErrorControl
== 1)
1408 else if (Service
->ErrorControl
== 2)
1410 if (IsLastKnownGood
== FALSE
)
1412 /* Boot last known good configuration */
1415 else if (Service
->ErrorControl
== 3)
1417 if (IsLastKnownGood
== FALSE
)
1419 /* Boot last known good configuration */
1433 * IopInitializeSystemDrivers
1435 * Load drivers marked as system start.
1445 IopInitializeSystemDrivers(VOID
)
1447 PSERVICE_GROUP CurrentGroup
;
1448 PSERVICE CurrentService
;
1452 DPRINT("IopInitializeSystemDrivers()\n");
1454 LIST_FOR_EACH(CurrentGroup
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1456 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1458 /* Load all drivers with a valid tag */
1459 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1461 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1463 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1464 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1465 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1466 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1468 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1469 Status
= IopLoadDriver(CurrentService
);
1474 /* Load all drivers without a tag or with an invalid tag */
1475 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1477 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1478 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1479 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1481 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1483 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1488 if (i
>= CurrentGroup
->TagCount
)
1490 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1491 Status
= IopLoadDriver(CurrentService
);
1498 DPRINT("IopInitializeSystemDrivers() done\n");
1504 * Unloads a device driver.
1508 * Name of the service to unload (registry key).
1511 * Whether to unload Plug & Plug or only legacy drivers. If this
1512 * parameter is set to FALSE, the routine will unload only legacy
1519 * Guard the whole function by SEH.
1523 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1525 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1526 UNICODE_STRING ImagePath
;
1527 UNICODE_STRING ServiceName
;
1528 UNICODE_STRING ObjectName
;
1529 PDRIVER_OBJECT DriverObject
;
1530 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1534 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1539 * Get the service name from the registry key name
1542 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1544 Start
= DriverServiceName
->Buffer
;
1548 RtlInitUnicodeString(&ServiceName
, Start
);
1551 * Construct the driver object name
1554 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1555 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1556 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1557 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1558 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1559 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1562 * Find the driver object
1565 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1566 KernelMode
, 0, (PVOID
*)&DriverObject
);
1568 if (!NT_SUCCESS(Status
))
1570 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1575 * Free the buffer for driver object name
1578 ExFreePool(ObjectName
.Buffer
);
1581 * Get path of service...
1584 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1586 RtlInitUnicodeString(&ImagePath
, NULL
);
1588 QueryTable
[0].Name
= L
"ImagePath";
1589 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1590 QueryTable
[0].EntryContext
= &ImagePath
;
1592 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1593 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1602 * Normalize the image path for all later processing.
1605 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1607 if (!NT_SUCCESS(Status
))
1609 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1614 * ... and check if it's loaded
1617 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1618 if (ModuleObject
== NULL
)
1620 return STATUS_UNSUCCESSFUL
;
1624 * Free the service path
1627 ExFreePool(ImagePath
.Buffer
);
1630 * Unload the module and release the references to the device object
1633 if (DriverObject
->DriverUnload
)
1634 (*DriverObject
->DriverUnload
)(DriverObject
);
1635 ObDereferenceObject(DriverObject
);
1636 ObDereferenceObject(DriverObject
);
1637 LdrUnloadModule(ModuleObject
);
1639 return STATUS_SUCCESS
;
1643 IopMarkLastReinitializeDriver(VOID
)
1647 KeAcquireSpinLock(&DriverReinitListLock
,
1650 if (IsListEmpty(&DriverReinitListHead
))
1652 DriverReinitTailEntry
= NULL
;
1656 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1659 KeReleaseSpinLock(&DriverReinitListLock
,
1665 IopReinitializeDrivers(VOID
)
1667 PDRIVER_REINIT_ITEM ReinitItem
;
1671 KeAcquireSpinLock(&DriverReinitListLock
,
1674 Entry
= DriverReinitTailEntry
;
1676 KeReleaseSpinLock(&DriverReinitListLock
,
1686 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1687 &DriverReinitListLock
);
1691 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1693 /* Increment reinitialization counter */
1694 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1696 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1697 ReinitItem
->Context
,
1698 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1702 if (Entry
== DriverReinitTailEntry
)
1707 /* PUBLIC FUNCTIONS ***********************************************************/
1716 IN PUNICODE_STRING DriverName
, OPTIONAL
1717 IN PDRIVER_INITIALIZE InitializationFunction
1720 WCHAR NameBuffer
[100];
1722 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1724 OBJECT_ATTRIBUTES ObjectAttributes
;
1726 PDRIVER_OBJECT DriverObject
;
1727 UNICODE_STRING ServiceKeyName
;
1731 /* First, create a unique name for the driver if we don't have one */
1734 /* Create a random name and set up the string*/
1735 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1736 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1737 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1738 LocalDriverName
.Buffer
= NameBuffer
;
1742 /* So we can avoid another code path, use a local var */
1743 LocalDriverName
= *DriverName
;
1746 /* Initialize the Attributes */
1747 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1748 InitializeObjectAttributes(&ObjectAttributes
,
1750 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1754 /* Create the Object */
1755 Status
= ObCreateObject(KernelMode
,
1763 (PVOID
*)&DriverObject
);
1765 /* Return on failure */
1766 if (!NT_SUCCESS(Status
)) return Status
;
1768 /* Set up the Object */
1769 RtlZeroMemory(DriverObject
, ObjectSize
);
1770 DriverObject
->Type
= IO_TYPE_DRIVER
;
1771 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1772 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1773 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1774 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1775 DriverObject
->DriverInit
= InitializationFunction
;
1777 /* Invalidate all Major Functions */
1778 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1780 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1783 /* Set up the Service Key Name */
1784 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1785 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1786 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1787 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1788 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1789 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1791 /* Also store it in the Driver Object. This is a bit of a hack. */
1792 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1794 /* Add the Object and get its handle */
1795 Status
= ObInsertObject(DriverObject
,
1802 /* Return on Failure */
1803 if (!NT_SUCCESS(Status
)) return Status
;
1805 /* Now reference it */
1806 Status
= ObReferenceObjectByHandle(hDriver
,
1810 (PVOID
*)&DriverObject
,
1814 /* Finally, call its init function */
1815 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1817 if (!NT_SUCCESS(Status
)) {
1818 /* If it didn't work, then kill the object */
1819 ObMakeTemporaryObject(DriverObject
);
1820 ObDereferenceObject(DriverObject
);
1823 /* Return the Status */
1833 IN PDRIVER_OBJECT DriverObject
1836 /* Simply derefence the Object */
1837 ObDereferenceObject(DriverObject
);
1844 * Loads a device driver.
1848 * Name of the service to load (registry key).
1858 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1860 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1861 UNICODE_STRING ImagePath
;
1862 UNICODE_STRING ServiceName
;
1863 UNICODE_STRING CapturedDriverServiceName
= {0};
1864 KPROCESSOR_MODE PreviousMode
;
1867 PDEVICE_NODE DeviceNode
;
1868 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1869 PDRIVER_OBJECT DriverObject
;
1874 PreviousMode
= KeGetPreviousMode();
1877 * Check security privileges
1880 /* FIXME: Uncomment when privileges will be correctly implemented. */
1882 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1884 DPRINT("Privilege not held\n");
1885 return STATUS_PRIVILEGE_NOT_HELD
;
1889 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1892 if (!NT_SUCCESS(Status
))
1897 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1899 RtlInitUnicodeString(&ImagePath
, NULL
);
1902 * Get the service name from the registry key name.
1904 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1906 ServiceName
= CapturedDriverServiceName
;
1907 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1908 while (CapturedDriverServiceName
.Buffer
!= cur
)
1912 ServiceName
.Buffer
= cur
+ 1;
1913 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1914 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1915 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1925 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1927 RtlInitUnicodeString(&ImagePath
, NULL
);
1929 QueryTable
[0].Name
= L
"Type";
1930 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1931 QueryTable
[0].EntryContext
= &Type
;
1933 QueryTable
[1].Name
= L
"ImagePath";
1934 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1935 QueryTable
[1].EntryContext
= &ImagePath
;
1937 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1938 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1940 if (!NT_SUCCESS(Status
))
1942 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1943 ExFreePool(ImagePath
.Buffer
);
1944 goto ReleaseCapturedString
;
1948 * Normalize the image path for all later processing.
1951 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1953 if (!NT_SUCCESS(Status
))
1955 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1956 goto ReleaseCapturedString
;
1959 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1960 DPRINT("Type: %lx\n", Type
);
1963 * See, if the driver module isn't already loaded
1966 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1967 if (ModuleObject
!= NULL
)
1969 DPRINT("Image already loaded\n");
1970 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1971 goto ReleaseCapturedString
;
1975 * Create device node
1978 /* Use IopRootDeviceNode for now */
1979 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1981 if (!NT_SUCCESS(Status
))
1983 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1984 goto ReleaseCapturedString
;
1988 * Load the driver module
1991 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1993 if (!NT_SUCCESS(Status
))
1995 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1996 IopFreeDeviceNode(DeviceNode
);
1997 goto ReleaseCapturedString
;
2001 * Set a service name for the device node
2004 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
2007 * Initialize the driver module
2010 Status
= IopInitializeDriverModule(
2013 &DeviceNode
->ServiceName
,
2014 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2015 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2018 if (!NT_SUCCESS(Status
))
2020 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
2021 LdrUnloadModule(ModuleObject
);
2022 IopFreeDeviceNode(DeviceNode
);
2023 goto ReleaseCapturedString
;
2026 IopInitializeDevice(DeviceNode
, DriverObject
);
2027 Status
= IopStartDevice(DeviceNode
);
2029 ReleaseCapturedString
:
2030 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2039 * Unloads a legacy device driver.
2043 * Name of the service to unload (registry key).
2053 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2055 return IopUnloadDriver(DriverServiceName
, FALSE
);
2059 * IoRegisterDriverReinitialization
2066 IoRegisterDriverReinitialization(
2067 PDRIVER_OBJECT DriverObject
,
2068 PDRIVER_REINITIALIZE ReinitRoutine
,
2071 PDRIVER_REINIT_ITEM ReinitItem
;
2073 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2074 if (ReinitItem
== NULL
)
2077 ReinitItem
->DriverObject
= DriverObject
;
2078 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2079 ReinitItem
->Context
= Context
;
2081 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2083 ExInterlockedInsertTailList(
2084 &DriverReinitListHead
,
2085 &ReinitItem
->ItemEntry
,
2086 &DriverReinitListLock
);
2094 IoRegisterBootDriverReinitialization(
2095 IN PDRIVER_OBJECT DriverObject
,
2096 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2100 PDRIVER_REINIT_ITEM ReinitItem
;
2102 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2103 if (ReinitItem
== NULL
)
2106 ReinitItem
->DriverObject
= DriverObject
;
2107 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2108 ReinitItem
->Context
= Context
;
2110 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2112 ExInterlockedInsertTailList(
2113 &DriverBootReinitListHead
,
2114 &ReinitItem
->ItemEntry
,
2115 &DriverReinitListLock
);
2119 * IoAllocateDriverObjectExtension
2126 IoAllocateDriverObjectExtension(
2127 PDRIVER_OBJECT DriverObject
,
2128 PVOID ClientIdentificationAddress
,
2129 ULONG DriverObjectExtensionSize
,
2130 PVOID
*DriverObjectExtension
)
2133 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2134 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2136 NewDriverExtension
= ExAllocatePoolWithTag(
2138 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2139 DriverObjectExtensionSize
,
2140 TAG_DRIVER_EXTENSION
);
2142 if (NewDriverExtension
== NULL
)
2144 return STATUS_INSUFFICIENT_RESOURCES
;
2147 OldIrql
= KeRaiseIrqlToDpcLevel();
2149 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2150 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2152 for (DriverExtensions
= DriverObject
->DriverSection
;
2153 DriverExtensions
!= NULL
;
2154 DriverExtensions
= DriverExtensions
->Link
)
2156 if (DriverExtensions
->ClientIdentificationAddress
==
2157 ClientIdentificationAddress
)
2159 KfLowerIrql(OldIrql
);
2160 return STATUS_OBJECT_NAME_COLLISION
;
2164 DriverObject
->DriverSection
= NewDriverExtension
;
2166 KfLowerIrql(OldIrql
);
2168 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2170 return STATUS_SUCCESS
;
2174 * IoGetDriverObjectExtension
2181 IoGetDriverObjectExtension(
2182 PDRIVER_OBJECT DriverObject
,
2183 PVOID ClientIdentificationAddress
)
2186 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2188 OldIrql
= KeRaiseIrqlToDpcLevel();
2190 for (DriverExtensions
= DriverObject
->DriverSection
;
2191 DriverExtensions
!= NULL
&&
2192 DriverExtensions
->ClientIdentificationAddress
!=
2193 ClientIdentificationAddress
;
2194 DriverExtensions
= DriverExtensions
->Link
)
2197 KfLowerIrql(OldIrql
);
2199 if (DriverExtensions
== NULL
)
2202 return &DriverExtensions
->Extension
;