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
;
22 typedef struct _SERVICE_GROUP
24 LIST_ENTRY GroupListEntry
;
25 UNICODE_STRING GroupName
;
26 BOOLEAN ServicesRunning
;
29 } SERVICE_GROUP
, *PSERVICE_GROUP
;
31 typedef struct _SERVICE
33 LIST_ENTRY ServiceListEntry
;
34 UNICODE_STRING ServiceName
;
35 UNICODE_STRING RegistryPath
;
36 UNICODE_STRING ServiceGroup
;
37 UNICODE_STRING ImagePath
;
44 /* BOOLEAN ServiceRunning;*/ // needed ??
47 typedef struct _DRIVER_REINIT_ITEM
50 PDRIVER_OBJECT DriverObject
;
51 PDRIVER_REINITIALIZE ReinitRoutine
;
53 } DRIVER_REINIT_ITEM
, *PDRIVER_REINIT_ITEM
;
55 /* GLOBALS ********************************************************************/
57 static LIST_ENTRY DriverReinitListHead
;
58 static KSPIN_LOCK DriverReinitListLock
;
59 static PLIST_ENTRY DriverReinitTailEntry
;
61 static PLIST_ENTRY DriverBootReinitTailEntry
;
62 static LIST_ENTRY DriverBootReinitListHead
;
63 static KSPIN_LOCK DriverBootReinitListLock
;
65 static LIST_ENTRY GroupListHead
= {NULL
, NULL
};
66 static LIST_ENTRY ServiceListHead
= {NULL
, NULL
};
68 static UNICODE_STRING IopHardwareDatabaseKey
=
69 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
71 POBJECT_TYPE IoDriverObjectType
= NULL
;
73 /* DECLARATIONS ***************************************************************/
76 IopDeleteDriver(PVOID ObjectBody
);
79 LdrProcessModule(PVOID ModuleLoadBase
,
80 PUNICODE_STRING ModuleName
,
81 PLDR_DATA_TABLE_ENTRY
*ModuleObject
);
86 IopDisplayLoadingMessage(PVOID ServiceName
,
89 static VOID INIT_FUNCTION
90 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
);
92 NTSTATUS FASTCALL INIT_FUNCTION
93 IopInitializeBuiltinDriver(
94 PDEVICE_NODE ModuleDeviceNode
,
99 static INIT_FUNCTION NTSTATUS
100 IopLoadDriver(PSERVICE Service
);
102 #if defined (ALLOC_PRAGMA)
103 #pragma alloc_text(INIT, IopInitDriverImplementation)
104 #pragma alloc_text(INIT, IopDisplayLoadingMessage)
105 #pragma alloc_text(INIT, IoCreateDriverList)
106 #pragma alloc_text(INIT, IoDestroyDriverList)
107 #pragma alloc_text(INIT, MiFreeBootDriverMemory)
108 #pragma alloc_text(INIT, IopInitializeBuiltinDriver)
109 #pragma alloc_text(INIT, IopLoadDriver)
113 /* PRIVATE FUNCTIONS **********************************************************/
117 IopInitDriverImplementation(VOID
)
119 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
122 DPRINT("Creating Registry Object Type\n");
124 /* Initialize the Driver object type */
125 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
126 RtlInitUnicodeString(&Name
, L
"Driver");
127 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
128 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DRIVER_OBJECT
);
129 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
130 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
131 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDriver
;
133 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoDriverObjectType
);
135 InitializeListHead(&DriverReinitListHead
);
136 KeInitializeSpinLock(&DriverReinitListLock
);
137 DriverReinitTailEntry
= NULL
;
139 InitializeListHead(&DriverBootReinitListHead
);
140 KeInitializeSpinLock(&DriverBootReinitListLock
);
141 DriverBootReinitTailEntry
= NULL
;
145 IopInvalidDeviceRequest(
146 PDEVICE_OBJECT DeviceObject
,
149 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
150 Irp
->IoStatus
.Information
= 0;
151 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
152 return STATUS_INVALID_DEVICE_REQUEST
;
156 IopDeleteDriver(PVOID ObjectBody
)
158 PDRIVER_OBJECT Object
= ObjectBody
;
160 PPRIVATE_DRIVER_EXTENSIONS DriverExtension
, NextDriverExtension
;
162 DPRINT("IopDeleteDriver(ObjectBody 0x%p)\n", ObjectBody
);
164 ExFreePool(Object
->DriverExtension
);
165 ExFreePool(Object
->DriverName
.Buffer
);
167 OldIrql
= KeRaiseIrqlToDpcLevel();
169 for (DriverExtension
= Object
->DriverSection
;
170 DriverExtension
!= NULL
;
171 DriverExtension
= NextDriverExtension
)
173 NextDriverExtension
= DriverExtension
->Link
;
174 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
177 KfLowerIrql(OldIrql
);
182 PDRIVER_OBJECT
*DriverObject
,
183 PUNICODE_STRING ServiceName
,
186 PDRIVER_OBJECT Object
;
187 WCHAR NameBuffer
[MAX_PATH
];
188 UNICODE_STRING DriverName
;
189 OBJECT_ATTRIBUTES ObjectAttributes
;
192 DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
193 DriverObject
, ServiceName
, FileSystem
);
195 *DriverObject
= NULL
;
197 /* Create ModuleName string */
198 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
199 /* We don't know which DriverObject we have to open */
200 return STATUS_INVALID_PARAMETER_2
;
202 DriverName
.Buffer
= NameBuffer
;
203 DriverName
.Length
= 0;
204 DriverName
.MaximumLength
= sizeof(NameBuffer
);
206 if (FileSystem
== TRUE
)
207 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
209 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
210 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
212 DPRINT("Driver name: '%wZ'\n", &DriverName
);
214 /* Initialize ObjectAttributes for driver object */
215 InitializeObjectAttributes(
218 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
,
222 /* Open driver object */
223 Status
= ObReferenceObjectByName(
226 NULL
, /* PassedAccessState */
227 0, /* DesiredAccess */
230 NULL
, /* ParseContext */
233 if (!NT_SUCCESS(Status
))
236 *DriverObject
= Object
;
238 return STATUS_SUCCESS
;
242 IopCreateDriverObject(
243 PDRIVER_OBJECT
*DriverObject
,
244 PUNICODE_STRING ServiceName
,
245 ULONG CreateAttributes
,
247 PVOID DriverImageStart
,
248 ULONG DriverImageSize
)
250 PDRIVER_OBJECT Object
;
251 WCHAR NameBuffer
[MAX_PATH
];
252 UNICODE_STRING DriverName
;
253 OBJECT_ATTRIBUTES ObjectAttributes
;
258 DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
259 DriverObject
, ServiceName
, FileSystem
, DriverImageStart
, DriverImageSize
);
261 *DriverObject
= NULL
;
263 /* Create ModuleName string */
264 if (ServiceName
!= NULL
&& ServiceName
->Buffer
!= NULL
)
266 if (FileSystem
== TRUE
)
267 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
269 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
270 wcscat(NameBuffer
, ServiceName
->Buffer
);
272 RtlInitUnicodeString(&DriverName
, NameBuffer
);
273 DPRINT("Driver name: '%wZ'\n", &DriverName
);
275 Buffer
= (PWSTR
)ExAllocatePool(PagedPool
, DriverName
.Length
+ sizeof(WCHAR
));
276 /* If we don't success, it is not a problem. Our driver
277 * object will not have associated driver name... */
281 RtlInitUnicodeString(&DriverName
, NULL
);
284 /* Initialize ObjectAttributes for driver object */
285 InitializeObjectAttributes(
288 CreateAttributes
| OBJ_PERMANENT
,
292 /* Create driver object */
293 Status
= ObCreateObject(
299 sizeof(DRIVER_OBJECT
),
304 if (!NT_SUCCESS(Status
))
309 Status
= ObInsertObject(Object
,
315 if (!NT_SUCCESS(Status
))
320 /* Create driver extension */
321 Object
->DriverExtension
= (PDRIVER_EXTENSION
)
322 ExAllocatePoolWithTag(
324 sizeof(DRIVER_EXTENSION
),
325 TAG_DRIVER_EXTENSION
);
327 if (Object
->DriverExtension
== NULL
)
329 return STATUS_NO_MEMORY
;
332 RtlZeroMemory(Object
->DriverExtension
, sizeof(DRIVER_EXTENSION
));
334 Object
->Type
= IO_TYPE_DRIVER
;
336 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
337 Object
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
339 Object
->HardwareDatabase
= &IopHardwareDatabaseKey
;
341 Object
->DriverStart
= DriverImageStart
;
342 Object
->DriverSize
= DriverImageSize
;
345 if (!Object
->DriverName
.Buffer
)
347 Object
->DriverName
.Buffer
= Buffer
;
348 Object
->DriverName
.Length
= DriverName
.Length
;
349 Object
->DriverName
.MaximumLength
= DriverName
.Length
+ sizeof(WCHAR
);
350 RtlCopyMemory(Object
->DriverName
.Buffer
, DriverName
.Buffer
, DriverName
.Length
);
351 Object
->DriverName
.Buffer
[Object
->DriverName
.Length
/ sizeof(WCHAR
)] = L
'\0';
357 *DriverObject
= Object
;
359 return STATUS_SUCCESS
;
363 * IopDisplayLoadingMessage
365 * Display 'Loading XXX...' message.
371 IopDisplayLoadingMessage(PVOID ServiceName
,
374 CHAR TextBuffer
[256];
375 if (SetupMode
) return;
378 sprintf(TextBuffer
, "Loading %S...\n", (PWCHAR
)ServiceName
);
382 sprintf(TextBuffer
, "Loading %s...\n", (PCHAR
)ServiceName
);
384 HalDisplayString(TextBuffer
);
388 * IopNormalizeImagePath
390 * Normalize an image path to contain complete path.
394 * The input path and on exit the result path. ImagePath.Buffer
395 * must be allocated by ExAllocatePool on input. Caller is responsible
396 * for freeing the buffer when it's no longer needed.
399 * Name of the service that ImagePath belongs to.
405 * The input image path isn't freed on error.
409 IopNormalizeImagePath(
410 IN OUT PUNICODE_STRING ImagePath
,
411 IN PUNICODE_STRING ServiceName
)
413 UNICODE_STRING InputImagePath
;
418 sizeof(UNICODE_STRING
));
420 if (InputImagePath
.Length
== 0)
422 ImagePath
->Length
= (33 * sizeof(WCHAR
)) + ServiceName
->Length
;
423 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
424 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
425 if (ImagePath
->Buffer
== NULL
)
426 return STATUS_NO_MEMORY
;
428 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\system32\\drivers\\");
429 wcscat(ImagePath
->Buffer
, ServiceName
->Buffer
);
430 wcscat(ImagePath
->Buffer
, L
".sys");
432 if (InputImagePath
.Buffer
[0] != L
'\\')
434 ImagePath
->Length
= (12 * sizeof(WCHAR
)) + InputImagePath
.Length
;
435 ImagePath
->MaximumLength
= ImagePath
->Length
+ sizeof(UNICODE_NULL
);
436 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
437 if (ImagePath
->Buffer
== NULL
)
438 return STATUS_NO_MEMORY
;
440 wcscpy(ImagePath
->Buffer
, L
"\\SystemRoot\\");
441 wcscat(ImagePath
->Buffer
, InputImagePath
.Buffer
);
442 ExFreePool(InputImagePath
.Buffer
);
445 return STATUS_SUCCESS
;
449 * IopLoadServiceModule
451 * Load a module specified by registry settings for service.
455 * Name of the service to load.
462 IopLoadServiceModule(
463 IN PUNICODE_STRING ServiceName
,
464 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
466 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
468 UNICODE_STRING ServiceImagePath
;
471 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
474 * Get information about the service.
477 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
479 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
481 QueryTable
[0].Name
= L
"Start";
482 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
483 QueryTable
[0].EntryContext
= &ServiceStart
;
485 QueryTable
[1].Name
= L
"ImagePath";
486 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
487 QueryTable
[1].EntryContext
= &ServiceImagePath
;
489 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
490 ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
492 if (!NT_SUCCESS(Status
))
494 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
498 //IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
501 * Normalize the image path for all later processing.
504 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
506 if (!NT_SUCCESS(Status
))
508 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
516 *ModuleObject
= LdrGetModuleObject(&ServiceImagePath
);
518 if (*ModuleObject
== NULL
)
520 Status
= STATUS_UNSUCCESSFUL
;
523 * Special case for boot modules that were loaded by boot loader.
526 if (ServiceStart
== 0)
529 CHAR SearchName
[256];
531 PLOADER_MODULE KeLoaderModules
=
532 (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
536 * Improve this searching algorithm by using the image name
537 * stored in registry entry ImageName and use the whole path
538 * (requires change in FreeLoader).
541 _snprintf(SearchName
, sizeof(SearchName
), "%wZ.sys", ServiceName
);
542 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
544 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
545 if (!_stricmp(ModuleName
, SearchName
))
547 DPRINT("Initializing boot module\n");
549 /* Tell, that the module is already loaded */
550 KeLoaderModules
[i
].Reserved
= 1;
552 Status
= LdrProcessModule(
553 (PVOID
)KeLoaderModules
[i
].ModStart
,
557 KDB_SYMBOLFILE_HOOK(SearchName
);
562 if (!NT_SUCCESS(Status
))
563 /* Try to load it. It may just have been installed by PnP manager */
564 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
568 * Case for rest of the drivers (except disabled)
571 else if (ServiceStart
< 4)
573 DPRINT("Loading module\n");
574 Status
= LdrLoadModule(&ServiceImagePath
, ModuleObject
);
579 DPRINT("Module already loaded\n");
580 Status
= STATUS_IMAGE_ALREADY_LOADED
;
583 ExFreePool(ServiceImagePath
.Buffer
);
586 * Now check if the module was loaded successfully.
589 if (!NT_SUCCESS(Status
))
591 DPRINT("Module loading failed (Status %x)\n", Status
);
594 DPRINT("Module loading (Status %x)\n", Status
);
600 * IopInitializeDriverModule
602 * Initalize a loaded driver.
606 * Pointer to device node.
609 * Module object representing the driver. It can be retrieve by
610 * IopLoadServiceModule.
613 * Name of the service (as in registry).
616 * Set to TRUE for file system drivers.
619 * On successful return this contains the driver object representing
624 IopInitializeDriverModule(
625 IN PDEVICE_NODE DeviceNode
,
626 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
627 IN PUNICODE_STRING ServiceName
,
628 IN BOOLEAN FileSystemDriver
,
629 OUT PDRIVER_OBJECT
*DriverObject
)
631 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
632 UNICODE_STRING RegistryKey
;
633 PDRIVER_INITIALIZE DriverEntry
;
636 DriverEntry
= ModuleObject
->EntryPoint
;
638 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
640 RegistryKey
.Length
= 0;
641 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
642 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
643 if (RegistryKey
.Buffer
== NULL
)
645 return STATUS_INSUFFICIENT_RESOURCES
;
647 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
648 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
652 RtlInitUnicodeString(&RegistryKey
, NULL
);
655 Status
= IopCreateDriverObject(
660 ModuleObject
->DllBase
,
661 ModuleObject
->SizeOfImage
);
663 if (!NT_SUCCESS(Status
))
665 DPRINT("IopCreateDriverObject failed (Status %x)\n", Status
);
669 DPRINT("RegistryKey: %wZ\n", &RegistryKey
);
670 DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry
);
672 IopMarkLastReinitializeDriver();
674 Status
= DriverEntry(*DriverObject
, &RegistryKey
);
676 RtlFreeUnicodeString(&RegistryKey
);
678 if (!NT_SUCCESS(Status
))
680 ObMakeTemporaryObject(*DriverObject
);
681 ObDereferenceObject(*DriverObject
);
685 IopReinitializeDrivers();
687 return STATUS_SUCCESS
;
691 * IopAttachFilterDriversCallback
693 * Internal routine used by IopAttachFilterDrivers.
697 IopAttachFilterDriversCallback(
705 PDEVICE_NODE DeviceNode
= Context
;
706 UNICODE_STRING ServiceName
;
708 PLDR_DATA_TABLE_ENTRY ModuleObject
;
709 PDRIVER_OBJECT DriverObject
;
712 for (Filters
= ValueData
;
713 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
715 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
717 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
718 ServiceName
.Buffer
= Filters
;
719 ServiceName
.MaximumLength
=
720 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
722 /* Load and initialize the filter driver */
723 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
724 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
726 if (!NT_SUCCESS(Status
))
729 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
730 FALSE
, &DriverObject
);
731 if (!NT_SUCCESS(Status
))
736 /* get existing DriverObject pointer */
737 Status
= IopGetDriverObject(
741 if (!NT_SUCCESS(Status
))
745 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
746 if (!NT_SUCCESS(Status
))
750 return STATUS_SUCCESS
;
754 * IopAttachFilterDrivers
756 * Load filter drivers for specified device node.
760 * Set to TRUE for loading lower level filters or FALSE for upper
765 IopAttachFilterDrivers(
766 PDEVICE_NODE DeviceNode
,
769 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
771 UNICODE_STRING Class
;
772 WCHAR ClassBuffer
[40];
776 * First load the device filters
779 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
781 QueryTable
[0].Name
= L
"LowerFilters";
783 QueryTable
[0].Name
= L
"UpperFilters";
784 QueryTable
[0].EntryContext
= NULL
;
785 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
786 QueryTable
[1].QueryRoutine
= NULL
;
787 QueryTable
[1].Name
= NULL
;
789 KeyBuffer
= ExAllocatePool(
791 (49 * sizeof(WCHAR
)) + DeviceNode
->InstancePath
.Length
);
792 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
793 wcscat(KeyBuffer
, DeviceNode
->InstancePath
.Buffer
);
795 RtlQueryRegistryValues(
796 RTL_REGISTRY_ABSOLUTE
,
803 * Now get the class GUID
807 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
808 Class
.Buffer
= ClassBuffer
;
809 QueryTable
[0].QueryRoutine
= NULL
;
810 QueryTable
[0].Name
= L
"ClassGUID";
811 QueryTable
[0].EntryContext
= &Class
;
812 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
814 Status
= RtlQueryRegistryValues(
815 RTL_REGISTRY_ABSOLUTE
,
821 ExFreePool(KeyBuffer
);
824 * Load the class filter driver
827 if (NT_SUCCESS(Status
))
829 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
831 QueryTable
[0].Name
= L
"LowerFilters";
833 QueryTable
[0].Name
= L
"UpperFilters";
834 QueryTable
[0].EntryContext
= NULL
;
835 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
837 KeyBuffer
= ExAllocatePool(PagedPool
, (58 * sizeof(WCHAR
)) + Class
.Length
);
838 wcscpy(KeyBuffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
839 wcscat(KeyBuffer
, ClassBuffer
);
841 RtlQueryRegistryValues(
842 RTL_REGISTRY_ABSOLUTE
,
848 ExFreePool(KeyBuffer
);
851 return STATUS_SUCCESS
;
854 static NTSTATUS STDCALL
855 IopGetGroupOrderList(PWSTR ValueName
,
862 PSERVICE_GROUP Group
;
864 DPRINT("IopGetGroupOrderList(%S, %x, 0x%p, %x, 0x%p, 0x%p)\n",
865 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
867 if (ValueType
== REG_BINARY
&&
869 ValueLength
>= sizeof(DWORD
) &&
870 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
872 Group
= (PSERVICE_GROUP
)Context
;
873 Group
->TagCount
= ((PULONG
)ValueData
)[0];
874 if (Group
->TagCount
> 0)
876 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
878 Group
->TagArray
= ExAllocatePool(NonPagedPool
, Group
->TagCount
* sizeof(DWORD
));
879 if (Group
->TagArray
== NULL
)
882 return STATUS_INSUFFICIENT_RESOURCES
;
884 memcpy(Group
->TagArray
, (PULONG
)ValueData
+ 1, Group
->TagCount
* sizeof(DWORD
));
889 return STATUS_UNSUCCESSFUL
;
893 return STATUS_SUCCESS
;
896 static NTSTATUS STDCALL
897 IopCreateGroupListEntry(PWSTR ValueName
,
904 PSERVICE_GROUP Group
;
905 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
909 if (ValueType
== REG_SZ
)
911 DPRINT("GroupName: '%S'\n", (PWCHAR
)ValueData
);
913 Group
= ExAllocatePool(NonPagedPool
,
914 sizeof(SERVICE_GROUP
));
917 return(STATUS_INSUFFICIENT_RESOURCES
);
920 RtlZeroMemory(Group
, sizeof(SERVICE_GROUP
));
922 if (!RtlCreateUnicodeString(&Group
->GroupName
, (PWSTR
)ValueData
))
925 return(STATUS_INSUFFICIENT_RESOURCES
);
928 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
929 QueryTable
[0].Name
= (PWSTR
)ValueData
;
930 QueryTable
[0].QueryRoutine
= IopGetGroupOrderList
;
932 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
937 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
939 InsertTailList(&GroupListHead
,
940 &Group
->GroupListEntry
);
943 return(STATUS_SUCCESS
);
947 static NTSTATUS STDCALL
948 IopCreateServiceListEntry(PUNICODE_STRING ServiceName
)
950 RTL_QUERY_REGISTRY_TABLE QueryTable
[7];
954 DPRINT("ServiceName: '%wZ'\n", ServiceName
);
956 /* Allocate service entry */
957 Service
= (PSERVICE
)ExAllocatePool(NonPagedPool
, sizeof(SERVICE
));
960 DPRINT1("ExAllocatePool() failed\n");
961 return(STATUS_INSUFFICIENT_RESOURCES
);
963 RtlZeroMemory(Service
, sizeof(SERVICE
));
965 /* Get service data */
966 RtlZeroMemory(&QueryTable
,
969 QueryTable
[0].Name
= L
"Start";
970 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
971 QueryTable
[0].EntryContext
= &Service
->Start
;
973 QueryTable
[1].Name
= L
"Type";
974 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
975 QueryTable
[1].EntryContext
= &Service
->Type
;
977 QueryTable
[2].Name
= L
"ErrorControl";
978 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
979 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
981 QueryTable
[3].Name
= L
"Group";
982 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
983 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
985 QueryTable
[4].Name
= L
"ImagePath";
986 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
987 QueryTable
[4].EntryContext
= &Service
->ImagePath
;
989 QueryTable
[5].Name
= L
"Tag";
990 QueryTable
[5].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
991 QueryTable
[5].EntryContext
= &Service
->Tag
;
993 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
998 if (!NT_SUCCESS(Status
) || Service
->Start
> 1)
1001 * If something goes wrong during RtlQueryRegistryValues
1002 * it'll just drop everything on the floor and return,
1003 * so you have to check if the buffers were filled.
1004 * Luckily we zerofilled the Service.
1006 if (Service
->ServiceGroup
.Buffer
)
1008 ExFreePool(Service
->ServiceGroup
.Buffer
);
1010 if (Service
->ImagePath
.Buffer
)
1012 ExFreePool(Service
->ImagePath
.Buffer
);
1014 ExFreePool(Service
);
1018 /* Copy service name */
1019 Service
->ServiceName
.Length
= ServiceName
->Length
;
1020 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
1021 Service
->ServiceName
.Buffer
= ExAllocatePool(NonPagedPool
,
1022 Service
->ServiceName
.MaximumLength
);
1023 RtlCopyMemory(Service
->ServiceName
.Buffer
,
1024 ServiceName
->Buffer
,
1025 ServiceName
->Length
);
1026 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
1028 /* Build registry path */
1029 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1030 Service
->RegistryPath
.Buffer
= ExAllocatePool(NonPagedPool
,
1031 MAX_PATH
* sizeof(WCHAR
));
1032 wcscpy(Service
->RegistryPath
.Buffer
,
1033 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
1034 wcscat(Service
->RegistryPath
.Buffer
,
1035 Service
->ServiceName
.Buffer
);
1036 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
1038 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
1039 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
1040 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
1041 DPRINT("ImagePath: '%wZ'\n", &Service
->ImagePath
);
1042 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
1043 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
1045 /* Append service entry */
1046 InsertTailList(&ServiceListHead
,
1047 &Service
->ServiceListEntry
);
1049 return(STATUS_SUCCESS
);
1053 NTSTATUS INIT_FUNCTION
1054 IoCreateDriverList(VOID
)
1056 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1057 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
1058 OBJECT_ATTRIBUTES ObjectAttributes
;
1059 UNICODE_STRING ServicesKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
1060 UNICODE_STRING SubKeyName
;
1065 ULONG KeyInfoLength
= 0;
1066 ULONG ReturnedLength
;
1068 DPRINT("IoCreateDriverList() called\n");
1070 /* Initialize basic variables */
1071 InitializeListHead(&GroupListHead
);
1072 InitializeListHead(&ServiceListHead
);
1074 /* Build group order list */
1075 RtlZeroMemory(&QueryTable
,
1076 sizeof(QueryTable
));
1078 QueryTable
[0].Name
= L
"List";
1079 QueryTable
[0].QueryRoutine
= IopCreateGroupListEntry
;
1081 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
1082 L
"ServiceGroupOrder",
1086 if (!NT_SUCCESS(Status
))
1089 /* Enumerate services and create the service list */
1090 InitializeObjectAttributes(&ObjectAttributes
,
1092 OBJ_CASE_INSENSITIVE
,
1096 Status
= ZwOpenKey(&KeyHandle
,
1097 KEY_ENUMERATE_SUB_KEYS
,
1099 if (!NT_SUCCESS(Status
))
1104 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
1105 KeyInfo
= ExAllocatePool(NonPagedPool
, KeyInfoLength
);
1106 if (KeyInfo
== NULL
)
1109 return(STATUS_INSUFFICIENT_RESOURCES
);
1115 Status
= ZwEnumerateKey(KeyHandle
,
1117 KeyBasicInformation
,
1121 if (NT_SUCCESS(Status
))
1123 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
1126 SubKeyName
.Length
= KeyInfo
->NameLength
;
1127 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
1128 SubKeyName
.Buffer
= KeyInfo
->Name
;
1129 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
1131 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
1132 IopCreateServiceListEntry(&SubKeyName
);
1136 if (!NT_SUCCESS(Status
))
1142 ExFreePool(KeyInfo
);
1145 DPRINT("IoCreateDriverList() done\n");
1147 return(STATUS_SUCCESS
);
1150 NTSTATUS INIT_FUNCTION
1151 IoDestroyDriverList(VOID
)
1153 PSERVICE_GROUP CurrentGroup
, tmp1
;
1154 PSERVICE CurrentService
, tmp2
;
1156 DPRINT("IoDestroyDriverList() called\n");
1158 /* Destroy group list */
1159 LIST_FOR_EACH_SAFE(CurrentGroup
, tmp1
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1161 ExFreePool(CurrentGroup
->GroupName
.Buffer
);
1162 RemoveEntryList(&CurrentGroup
->GroupListEntry
);
1163 if (CurrentGroup
->TagArray
)
1165 ExFreePool(CurrentGroup
->TagArray
);
1167 ExFreePool(CurrentGroup
);
1170 /* Destroy service list */
1171 LIST_FOR_EACH_SAFE(CurrentService
, tmp2
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1173 ExFreePool(CurrentService
->ServiceName
.Buffer
);
1174 ExFreePool(CurrentService
->RegistryPath
.Buffer
);
1175 ExFreePool(CurrentService
->ServiceGroup
.Buffer
);
1176 ExFreePool(CurrentService
->ImagePath
.Buffer
);
1177 RemoveEntryList(&CurrentService
->ServiceListEntry
);
1178 ExFreePool(CurrentService
);
1181 DPRINT("IoDestroyDriverList() done\n");
1183 return(STATUS_SUCCESS
);
1186 static VOID INIT_FUNCTION
1187 MiFreeBootDriverMemory(PVOID StartAddress
, ULONG Length
)
1191 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1193 MmDeleteVirtualMapping(NULL
, (char*)StartAddress
+ i
* PAGE_SIZE
, TRUE
, NULL
, NULL
);
1198 * IopInitializeBuiltinDriver
1200 * Initialize a driver that is already loaded in memory.
1203 NTSTATUS FASTCALL INIT_FUNCTION
1204 IopInitializeBuiltinDriver(
1205 PDEVICE_NODE ModuleDeviceNode
,
1206 PVOID ModuleLoadBase
,
1210 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1211 PDEVICE_NODE DeviceNode
;
1212 PDRIVER_OBJECT DriverObject
;
1214 PCHAR FileNameWithoutPath
;
1215 LPWSTR FileExtension
;
1217 DPRINT("Initializing driver '%s' at %08lx, length 0x%08lx\n",
1218 FileName
, ModuleLoadBase
, ModuleLength
);
1221 * Display 'Loading XXX...' message
1223 IopDisplayLoadingMessage(FileName
, FALSE
);
1226 * Determine the right device object
1229 if (ModuleDeviceNode
== NULL
)
1231 /* Use IopRootDeviceNode for now */
1232 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1233 if (!NT_SUCCESS(Status
))
1235 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1240 DeviceNode
= ModuleDeviceNode
;
1244 * Generate filename without path (not needed by freeldr)
1247 FileNameWithoutPath
= strrchr(FileName
, '\\');
1248 if (FileNameWithoutPath
== NULL
)
1250 FileNameWithoutPath
= FileName
;
1257 RtlCreateUnicodeStringFromAsciiz(&DeviceNode
->ServiceName
,
1258 FileNameWithoutPath
);
1259 Status
= LdrProcessModule(ModuleLoadBase
, &DeviceNode
->ServiceName
,
1261 if (!NT_SUCCESS(Status
))
1263 if (ModuleDeviceNode
== NULL
)
1264 IopFreeDeviceNode(DeviceNode
);
1265 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1270 KDB_SYMBOLFILE_HOOK(FileName
);
1273 * Strip the file extension from ServiceName
1276 FileExtension
= wcsrchr(DeviceNode
->ServiceName
.Buffer
, '.');
1277 if (FileExtension
!= NULL
)
1279 DeviceNode
->ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
1280 FileExtension
[0] = 0;
1284 * Initialize the driver
1287 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
,
1288 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
1290 if (!NT_SUCCESS(Status
))
1292 if (ModuleDeviceNode
== NULL
)
1293 IopFreeDeviceNode(DeviceNode
);
1294 CPRINT("Driver '%s' load failed, status (%x)\n", FileName
, Status
);
1298 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
1299 if (NT_SUCCESS(Status
))
1301 Status
= IopStartDevice(DeviceNode
);
1308 * IopInitializeBootDrivers
1310 * Initialize boot drivers and free memory for boot files.
1320 IopInitializeBootDrivers(VOID
)
1322 ULONG BootDriverCount
;
1328 PLOADER_MODULE KeLoaderModules
= (PLOADER_MODULE
)KeLoaderBlock
.ModsAddr
;
1330 UNICODE_STRING DriverName
;
1333 DPRINT("IopInitializeBootDrivers()\n");
1335 BootDriverCount
= 0;
1336 for (i
= 0; i
< KeLoaderBlock
.ModsCount
; i
++)
1338 ModuleStart
= KeLoaderModules
[i
].ModStart
;
1339 ModuleSize
= KeLoaderModules
[i
].ModEnd
- ModuleStart
;
1340 ModuleName
= (PCHAR
)KeLoaderModules
[i
].String
;
1341 ModuleLoaded
= KeLoaderModules
[i
].Reserved
;
1342 Extension
= strrchr(ModuleName
, '.');
1343 if (Extension
== NULL
)
1346 if (!_stricmp(Extension
, ".sym") || !_stricmp(Extension
, ".dll"))
1348 /* Process symbols for *.exe and *.dll */
1349 KDB_SYMBOLFILE_HOOK(ModuleName
);
1351 /* Log *.exe and *.dll files */
1352 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1353 IopBootLog(&DriverName
, TRUE
);
1354 RtlFreeUnicodeString(&DriverName
);
1356 else if (!_stricmp(Extension
, ".sys"))
1358 /* Initialize and log boot start driver */
1361 Status
= IopInitializeBuiltinDriver(NULL
,
1365 RtlCreateUnicodeStringFromAsciiz(&DriverName
, ModuleName
);
1366 IopBootLog(&DriverName
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1367 RtlFreeUnicodeString(&DriverName
);
1374 * Free memory for all boot files, except ntoskrnl.exe.
1376 for (i
= 1; i
< KeLoaderBlock
.ModsCount
; i
++)
1378 MiFreeBootDriverMemory((PVOID
)KeLoaderModules
[i
].ModStart
,
1379 KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
);
1382 KeLoaderBlock
.ModsCount
= 0;
1384 if (BootDriverCount
== 0)
1386 DbgPrint("No boot drivers available.\n");
1387 KEBUGCHECK(INACCESSIBLE_BOOT_DEVICE
);
1391 static INIT_FUNCTION NTSTATUS
1392 IopLoadDriver(PSERVICE Service
)
1394 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1396 IopDisplayLoadingMessage(Service
->ServiceName
.Buffer
, TRUE
);
1397 Status
= ZwLoadDriver(&Service
->RegistryPath
);
1398 IopBootLog(&Service
->ImagePath
, NT_SUCCESS(Status
) ? TRUE
: FALSE
);
1399 if (!NT_SUCCESS(Status
))
1401 DPRINT("IopLoadDriver() failed (Status %lx)\n", Status
);
1403 if (Service
->ErrorControl
== 1)
1407 else if (Service
->ErrorControl
== 2)
1409 if (IsLastKnownGood
== FALSE
)
1411 /* Boot last known good configuration */
1414 else if (Service
->ErrorControl
== 3)
1416 if (IsLastKnownGood
== FALSE
)
1418 /* Boot last known good configuration */
1432 * IopInitializeSystemDrivers
1434 * Load drivers marked as system start.
1444 IopInitializeSystemDrivers(VOID
)
1446 PSERVICE_GROUP CurrentGroup
;
1447 PSERVICE CurrentService
;
1451 DPRINT("IopInitializeSystemDrivers()\n");
1453 LIST_FOR_EACH(CurrentGroup
, &GroupListHead
, SERVICE_GROUP
, GroupListEntry
)
1455 DPRINT("Group: %wZ\n", &CurrentGroup
->GroupName
);
1457 /* Load all drivers with a valid tag */
1458 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1460 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1462 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1463 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1464 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/) &&
1465 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
1467 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1468 Status
= IopLoadDriver(CurrentService
);
1473 /* Load all drivers without a tag or with an invalid tag */
1474 LIST_FOR_EACH(CurrentService
, &ServiceListHead
, SERVICE
, ServiceListEntry
)
1476 if ((RtlCompareUnicodeString(&CurrentGroup
->GroupName
,
1477 &CurrentService
->ServiceGroup
, TRUE
) == 0) &&
1478 (CurrentService
->Start
== 1 /*SERVICE_SYSTEM_START*/))
1480 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1482 if (CurrentGroup
->TagArray
[i
] == CurrentService
->Tag
)
1487 if (i
>= CurrentGroup
->TagCount
)
1489 DPRINT(" Path: %wZ\n", &CurrentService
->RegistryPath
);
1490 Status
= IopLoadDriver(CurrentService
);
1497 DPRINT("IopInitializeSystemDrivers() done\n");
1503 * Unloads a device driver.
1507 * Name of the service to unload (registry key).
1510 * Whether to unload Plug & Plug or only legacy drivers. If this
1511 * parameter is set to FALSE, the routine will unload only legacy
1518 * Guard the whole function by SEH.
1522 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
1524 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
1525 UNICODE_STRING ImagePath
;
1526 UNICODE_STRING ServiceName
;
1527 UNICODE_STRING ObjectName
;
1528 PDRIVER_OBJECT DriverObject
;
1529 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1533 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
1538 * Get the service name from the registry key name
1541 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
1543 Start
= DriverServiceName
->Buffer
;
1547 RtlInitUnicodeString(&ServiceName
, Start
);
1550 * Construct the driver object name
1553 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
1554 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
1555 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
1556 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
1557 memcpy(ObjectName
.Buffer
+ 8, Start
, (ObjectName
.Length
- 8) * sizeof(WCHAR
));
1558 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1561 * Find the driver object
1564 Status
= ObReferenceObjectByName(&ObjectName
, 0, 0, 0, IoDriverObjectType
,
1565 KernelMode
, 0, (PVOID
*)&DriverObject
);
1567 if (!NT_SUCCESS(Status
))
1569 DPRINT("Can't locate driver object for %wZ\n", ObjectName
);
1574 * Free the buffer for driver object name
1577 ExFreePool(ObjectName
.Buffer
);
1580 * Get path of service...
1583 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1585 RtlInitUnicodeString(&ImagePath
, NULL
);
1587 QueryTable
[0].Name
= L
"ImagePath";
1588 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1589 QueryTable
[0].EntryContext
= &ImagePath
;
1591 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1592 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1594 if (!NT_SUCCESS(Status
))
1596 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1601 * Normalize the image path for all later processing.
1604 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1606 if (!NT_SUCCESS(Status
))
1608 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1613 * ... and check if it's loaded
1616 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1617 if (ModuleObject
== NULL
)
1619 return STATUS_UNSUCCESSFUL
;
1623 * Free the service path
1626 ExFreePool(ImagePath
.Buffer
);
1629 * Unload the module and release the references to the device object
1632 if (DriverObject
->DriverUnload
)
1633 (*DriverObject
->DriverUnload
)(DriverObject
);
1634 ObDereferenceObject(DriverObject
);
1635 ObDereferenceObject(DriverObject
);
1636 LdrUnloadModule(ModuleObject
);
1638 return STATUS_SUCCESS
;
1642 IopMarkLastReinitializeDriver(VOID
)
1646 KeAcquireSpinLock(&DriverReinitListLock
,
1649 if (IsListEmpty(&DriverReinitListHead
))
1651 DriverReinitTailEntry
= NULL
;
1655 DriverReinitTailEntry
= DriverReinitListHead
.Blink
;
1658 KeReleaseSpinLock(&DriverReinitListLock
,
1664 IopReinitializeDrivers(VOID
)
1666 PDRIVER_REINIT_ITEM ReinitItem
;
1670 KeAcquireSpinLock(&DriverReinitListLock
,
1673 Entry
= DriverReinitTailEntry
;
1675 KeReleaseSpinLock(&DriverReinitListLock
,
1685 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1686 &DriverReinitListLock
);
1690 ReinitItem
= (PDRIVER_REINIT_ITEM
)CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1692 /* Increment reinitialization counter */
1693 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1695 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1696 ReinitItem
->Context
,
1697 ReinitItem
->DriverObject
->DriverExtension
->Count
);
1701 if (Entry
== DriverReinitTailEntry
)
1706 /* PUBLIC FUNCTIONS ***********************************************************/
1715 IN PUNICODE_STRING DriverName
, OPTIONAL
1716 IN PDRIVER_INITIALIZE InitializationFunction
1719 WCHAR NameBuffer
[100];
1721 UNICODE_STRING LocalDriverName
; /* To reduce code if no name given */
1723 OBJECT_ATTRIBUTES ObjectAttributes
;
1725 PDRIVER_OBJECT DriverObject
;
1726 UNICODE_STRING ServiceKeyName
;
1730 /* First, create a unique name for the driver if we don't have one */
1733 /* Create a random name and set up the string*/
1734 NameLength
= swprintf(NameBuffer
, L
"\\Driver\\%08u", KeTickCount
);
1735 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1736 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1737 LocalDriverName
.Buffer
= NameBuffer
;
1741 /* So we can avoid another code path, use a local var */
1742 LocalDriverName
= *DriverName
;
1745 /* Initialize the Attributes */
1746 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(DRIVER_EXTENSION
);
1747 InitializeObjectAttributes(&ObjectAttributes
,
1749 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1753 /* Create the Object */
1754 Status
= ObCreateObject(KernelMode
,
1762 (PVOID
*)&DriverObject
);
1764 /* Return on failure */
1765 if (!NT_SUCCESS(Status
)) return Status
;
1767 /* Set up the Object */
1768 RtlZeroMemory(DriverObject
, ObjectSize
);
1769 DriverObject
->Type
= IO_TYPE_DRIVER
;
1770 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1771 DriverObject
->Flags
= DRVO_BUILTIN_DRIVER
;
1772 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1773 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1774 DriverObject
->DriverInit
= InitializationFunction
;
1776 /* Invalidate all Major Functions */
1777 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1779 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1782 /* Set up the Service Key Name */
1783 ServiceKeyName
.Buffer
= ExAllocatePool(PagedPool
, LocalDriverName
.Length
+ sizeof(WCHAR
));
1784 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1785 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1786 RtlMoveMemory(ServiceKeyName
.Buffer
, LocalDriverName
.Buffer
, LocalDriverName
.Length
);
1787 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = L
'\0';
1788 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1790 /* Also store it in the Driver Object. This is a bit of a hack. */
1791 RtlMoveMemory(&DriverObject
->DriverName
, &ServiceKeyName
, sizeof(UNICODE_STRING
));
1793 /* Add the Object and get its handle */
1794 Status
= ObInsertObject(DriverObject
,
1801 /* Return on Failure */
1802 if (!NT_SUCCESS(Status
)) return Status
;
1804 /* Now reference it */
1805 Status
= ObReferenceObjectByHandle(hDriver
,
1809 (PVOID
*)&DriverObject
,
1813 /* Finally, call its init function */
1814 Status
= (*InitializationFunction
)(DriverObject
, NULL
);
1816 if (!NT_SUCCESS(Status
)) {
1817 /* If it didn't work, then kill the object */
1818 ObMakeTemporaryObject(DriverObject
);
1819 ObDereferenceObject(DriverObject
);
1822 /* Return the Status */
1832 IN PDRIVER_OBJECT DriverObject
1835 /* Simply derefence the Object */
1836 ObDereferenceObject(DriverObject
);
1843 * Loads a device driver.
1847 * Name of the service to load (registry key).
1857 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1859 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1860 UNICODE_STRING ImagePath
;
1861 UNICODE_STRING ServiceName
;
1862 UNICODE_STRING CapturedDriverServiceName
= {0};
1863 KPROCESSOR_MODE PreviousMode
;
1866 PDEVICE_NODE DeviceNode
;
1867 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1868 PDRIVER_OBJECT DriverObject
;
1873 PreviousMode
= KeGetPreviousMode();
1876 * Check security privileges
1879 /* FIXME: Uncomment when privileges will be correctly implemented. */
1881 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1883 DPRINT("Privilege not held\n");
1884 return STATUS_PRIVILEGE_NOT_HELD
;
1888 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1891 if (!NT_SUCCESS(Status
))
1896 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1898 RtlInitUnicodeString(&ImagePath
, NULL
);
1901 * Get the service name from the registry key name.
1903 ASSERT(CapturedDriverServiceName
.Length
>= sizeof(WCHAR
));
1905 ServiceName
= CapturedDriverServiceName
;
1906 cur
= CapturedDriverServiceName
.Buffer
+ (CapturedDriverServiceName
.Length
/ sizeof(WCHAR
)) - 1;
1907 while (CapturedDriverServiceName
.Buffer
!= cur
)
1911 ServiceName
.Buffer
= cur
+ 1;
1912 ServiceName
.Length
= CapturedDriverServiceName
.Length
-
1913 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1914 (ULONG_PTR
)CapturedDriverServiceName
.Buffer
);
1924 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1926 RtlInitUnicodeString(&ImagePath
, NULL
);
1928 QueryTable
[0].Name
= L
"Type";
1929 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1930 QueryTable
[0].EntryContext
= &Type
;
1932 QueryTable
[1].Name
= L
"ImagePath";
1933 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1934 QueryTable
[1].EntryContext
= &ImagePath
;
1936 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1937 CapturedDriverServiceName
.Buffer
, QueryTable
, NULL
, NULL
);
1939 if (!NT_SUCCESS(Status
))
1941 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1942 ExFreePool(ImagePath
.Buffer
);
1943 goto ReleaseCapturedString
;
1947 * Normalize the image path for all later processing.
1950 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1952 if (!NT_SUCCESS(Status
))
1954 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1955 goto ReleaseCapturedString
;
1958 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1959 DPRINT("Type: %lx\n", Type
);
1962 * See, if the driver module isn't already loaded
1965 ModuleObject
= LdrGetModuleObject(&ImagePath
);
1966 if (ModuleObject
!= NULL
)
1968 DPRINT("Image already loaded\n");
1969 Status
= STATUS_IMAGE_ALREADY_LOADED
;
1970 goto ReleaseCapturedString
;
1974 * Create device node
1977 /* Use IopRootDeviceNode for now */
1978 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &DeviceNode
);
1980 if (!NT_SUCCESS(Status
))
1982 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1983 goto ReleaseCapturedString
;
1987 * Load the driver module
1990 Status
= LdrLoadModule(&ImagePath
, &ModuleObject
);
1992 if (!NT_SUCCESS(Status
))
1994 DPRINT("LdrLoadModule() failed (Status %lx)\n", Status
);
1995 IopFreeDeviceNode(DeviceNode
);
1996 goto ReleaseCapturedString
;
2000 * Set a service name for the device node
2003 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
2006 * Initialize the driver module
2009 Status
= IopInitializeDriverModule(
2012 &DeviceNode
->ServiceName
,
2013 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
2014 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
2017 if (!NT_SUCCESS(Status
))
2019 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
2020 LdrUnloadModule(ModuleObject
);
2021 IopFreeDeviceNode(DeviceNode
);
2022 goto ReleaseCapturedString
;
2025 IopInitializeDevice(DeviceNode
, DriverObject
);
2026 Status
= IopStartDevice(DeviceNode
);
2028 ReleaseCapturedString
:
2029 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
2038 * Unloads a legacy device driver.
2042 * Name of the service to unload (registry key).
2052 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
2054 return IopUnloadDriver(DriverServiceName
, FALSE
);
2058 * IoRegisterDriverReinitialization
2065 IoRegisterDriverReinitialization(
2066 PDRIVER_OBJECT DriverObject
,
2067 PDRIVER_REINITIALIZE ReinitRoutine
,
2070 PDRIVER_REINIT_ITEM ReinitItem
;
2072 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2073 if (ReinitItem
== NULL
)
2076 ReinitItem
->DriverObject
= DriverObject
;
2077 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
2078 ReinitItem
->Context
= Context
;
2080 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
2082 ExInterlockedInsertTailList(
2083 &DriverReinitListHead
,
2084 &ReinitItem
->ItemEntry
,
2085 &DriverReinitListLock
);
2093 IoRegisterBootDriverReinitialization(
2094 IN PDRIVER_OBJECT DriverObject
,
2095 IN PDRIVER_REINITIALIZE DriverReinitializationRoutine
,
2099 PDRIVER_REINIT_ITEM ReinitItem
;
2101 ReinitItem
= ExAllocatePool(NonPagedPool
, sizeof(DRIVER_REINIT_ITEM
));
2102 if (ReinitItem
== NULL
)
2105 ReinitItem
->DriverObject
= DriverObject
;
2106 ReinitItem
->ReinitRoutine
= DriverReinitializationRoutine
;
2107 ReinitItem
->Context
= Context
;
2109 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
2111 ExInterlockedInsertTailList(
2112 &DriverBootReinitListHead
,
2113 &ReinitItem
->ItemEntry
,
2114 &DriverReinitListLock
);
2118 * IoAllocateDriverObjectExtension
2125 IoAllocateDriverObjectExtension(
2126 PDRIVER_OBJECT DriverObject
,
2127 PVOID ClientIdentificationAddress
,
2128 ULONG DriverObjectExtensionSize
,
2129 PVOID
*DriverObjectExtension
)
2132 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2133 PPRIVATE_DRIVER_EXTENSIONS NewDriverExtension
;
2135 NewDriverExtension
= ExAllocatePoolWithTag(
2137 sizeof(PRIVATE_DRIVER_EXTENSIONS
) - sizeof(CHAR
) +
2138 DriverObjectExtensionSize
,
2139 TAG_DRIVER_EXTENSION
);
2141 if (NewDriverExtension
== NULL
)
2143 return STATUS_INSUFFICIENT_RESOURCES
;
2146 OldIrql
= KeRaiseIrqlToDpcLevel();
2148 NewDriverExtension
->Link
= DriverObject
->DriverSection
;
2149 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
2151 for (DriverExtensions
= DriverObject
->DriverSection
;
2152 DriverExtensions
!= NULL
;
2153 DriverExtensions
= DriverExtensions
->Link
)
2155 if (DriverExtensions
->ClientIdentificationAddress
==
2156 ClientIdentificationAddress
)
2158 KfLowerIrql(OldIrql
);
2159 return STATUS_OBJECT_NAME_COLLISION
;
2163 DriverObject
->DriverSection
= NewDriverExtension
;
2165 KfLowerIrql(OldIrql
);
2167 *DriverObjectExtension
= &NewDriverExtension
->Extension
;
2169 return STATUS_SUCCESS
;
2173 * IoGetDriverObjectExtension
2180 IoGetDriverObjectExtension(
2181 PDRIVER_OBJECT DriverObject
,
2182 PVOID ClientIdentificationAddress
)
2185 PPRIVATE_DRIVER_EXTENSIONS DriverExtensions
;
2187 OldIrql
= KeRaiseIrqlToDpcLevel();
2189 for (DriverExtensions
= DriverObject
->DriverSection
;
2190 DriverExtensions
!= NULL
&&
2191 DriverExtensions
->ClientIdentificationAddress
!=
2192 ClientIdentificationAddress
;
2193 DriverExtensions
= DriverExtensions
->Link
)
2196 KfLowerIrql(OldIrql
);
2198 if (DriverExtensions
== NULL
)
2201 return &DriverExtensions
->Extension
;