2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/driver.c
5 * PURPOSE: Driver Object Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Filip Navara (navaraf@reactos.org)
8 * Hervé Poussineau (hpoussin@reactos.org)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 LIST_ENTRY DriverReinitListHead
;
20 KSPIN_LOCK DriverReinitListLock
;
21 PLIST_ENTRY DriverReinitTailEntry
;
23 PLIST_ENTRY DriverBootReinitTailEntry
;
24 LIST_ENTRY DriverBootReinitListHead
;
25 KSPIN_LOCK DriverBootReinitListLock
;
27 UNICODE_STRING IopHardwareDatabaseKey
=
28 RTL_CONSTANT_STRING(L
"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
30 POBJECT_TYPE IoDriverObjectType
= NULL
;
32 #define TAG_RTLREGISTRY 'vrqR'
34 extern BOOLEAN ExpInTextModeSetup
;
35 extern BOOLEAN PnpSystemInit
;
37 /* PRIVATE FUNCTIONS **********************************************************/
40 IopInvalidDeviceRequest(
41 PDEVICE_OBJECT DeviceObject
,
44 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
45 Irp
->IoStatus
.Information
= 0;
46 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
47 return STATUS_INVALID_DEVICE_REQUEST
;
52 IopDeleteDriver(IN PVOID ObjectBody
)
54 PDRIVER_OBJECT DriverObject
= ObjectBody
;
55 PIO_CLIENT_EXTENSION DriverExtension
, NextDriverExtension
;
58 /* Get the extension and loop them */
59 DriverExtension
= IoGetDrvObjExtension(DriverObject
)->
60 ClientDriverExtension
;
61 while (DriverExtension
)
63 /* Get the next one */
64 NextDriverExtension
= DriverExtension
->NextExtension
;
65 ExFreePoolWithTag(DriverExtension
, TAG_DRIVER_EXTENSION
);
68 DriverExtension
= NextDriverExtension
;
71 /* Check if the driver image is still loaded */
72 if (DriverObject
->DriverSection
)
75 MmUnloadSystemImage(DriverObject
->DriverSection
);
78 /* Check if it has a name */
79 if (DriverObject
->DriverName
.Buffer
)
82 ExFreePool(DriverObject
->DriverName
.Buffer
);
85 #if 0 /* See a bit of hack in IopCreateDriver */
86 /* Check if it has a service key name */
87 if (DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
)
90 ExFreePool(DriverObject
->DriverExtension
->ServiceKeyName
.Buffer
);
97 PDRIVER_OBJECT
*DriverObject
,
98 PUNICODE_STRING ServiceName
,
101 PDRIVER_OBJECT Object
;
102 WCHAR NameBuffer
[MAX_PATH
];
103 UNICODE_STRING DriverName
;
106 DPRINT("IopGetDriverObject(%p '%wZ' %x)\n",
107 DriverObject
, ServiceName
, FileSystem
);
109 *DriverObject
= NULL
;
111 /* Create ModuleName string */
112 if (ServiceName
== NULL
|| ServiceName
->Buffer
== NULL
)
113 /* We don't know which DriverObject we have to open */
114 return STATUS_INVALID_PARAMETER_2
;
116 DriverName
.Buffer
= NameBuffer
;
117 DriverName
.Length
= 0;
118 DriverName
.MaximumLength
= sizeof(NameBuffer
);
120 if (FileSystem
== TRUE
)
121 RtlAppendUnicodeToString(&DriverName
, FILESYSTEM_ROOT_NAME
);
123 RtlAppendUnicodeToString(&DriverName
, DRIVER_ROOT_NAME
);
124 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
126 DPRINT("Driver name: '%wZ'\n", &DriverName
);
128 /* Open driver object */
129 Status
= ObReferenceObjectByName(
131 OBJ_OPENIF
| OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
, /* Attributes */
132 NULL
, /* PassedAccessState */
133 0, /* DesiredAccess */
136 NULL
, /* ParseContext */
139 if (!NT_SUCCESS(Status
))
141 DPRINT("Failed to reference driver object, status=0x%08x\n", Status
);
145 *DriverObject
= Object
;
147 DPRINT("Driver Object: %p\n", Object
);
149 return STATUS_SUCCESS
;
153 * IopDisplayLoadingMessage
155 * Display 'Loading XXX...' message.
161 IopDisplayLoadingMessage(PUNICODE_STRING ServiceName
)
163 CHAR TextBuffer
[256];
165 if (ExpInTextModeSetup
) return;
166 RtlUpcaseUnicodeString(ServiceName
, ServiceName
, FALSE
);
167 snprintf(TextBuffer
, sizeof(TextBuffer
),
169 KeLoaderBlock
->ArcBootDeviceName
,
170 KeLoaderBlock
->NtBootPathName
,
173 if (!strstr(TextBuffer
, ".sys"))
174 strcat(TextBuffer
, ".sys\n");
176 strcat(TextBuffer
, "\n");
177 HalDisplayString(TextBuffer
);
181 * IopNormalizeImagePath
183 * Normalize an image path to contain complete path.
187 * The input path and on exit the result path. ImagePath.Buffer
188 * must be allocated by ExAllocatePool on input. Caller is responsible
189 * for freeing the buffer when it's no longer needed.
192 * Name of the service that ImagePath belongs to.
198 * The input image path isn't freed on error.
202 IopNormalizeImagePath(
203 IN OUT PUNICODE_STRING ImagePath
,
204 IN PUNICODE_STRING ServiceName
)
206 UNICODE_STRING InputImagePath
;
211 sizeof(UNICODE_STRING
));
213 if (InputImagePath
.Length
== 0)
215 ImagePath
->Length
= 0;
216 ImagePath
->MaximumLength
=
217 (33 * sizeof(WCHAR
)) + ServiceName
->Length
+ sizeof(UNICODE_NULL
);
218 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
219 if (ImagePath
->Buffer
== NULL
)
220 return STATUS_NO_MEMORY
;
222 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\system32\\drivers\\");
223 RtlAppendUnicodeStringToString(ImagePath
, ServiceName
);
224 RtlAppendUnicodeToString(ImagePath
, L
".sys");
226 if (InputImagePath
.Buffer
[0] != L
'\\')
228 ImagePath
->Length
= 0;
229 ImagePath
->MaximumLength
=
230 12 * sizeof(WCHAR
) + InputImagePath
.Length
+ sizeof(UNICODE_NULL
);
231 ImagePath
->Buffer
= ExAllocatePool(NonPagedPool
, ImagePath
->MaximumLength
);
232 if (ImagePath
->Buffer
== NULL
)
233 return STATUS_NO_MEMORY
;
235 RtlAppendUnicodeToString(ImagePath
, L
"\\SystemRoot\\");
236 RtlAppendUnicodeStringToString(ImagePath
, &InputImagePath
);
238 /* Free caller's string */
239 ExFreePoolWithTag(InputImagePath
.Buffer
, TAG_RTLREGISTRY
);
242 return STATUS_SUCCESS
;
246 * IopLoadServiceModule
248 * Load a module specified by registry settings for service.
252 * Name of the service to load.
259 IopLoadServiceModule(
260 IN PUNICODE_STRING ServiceName
,
261 OUT PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
263 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
265 UNICODE_STRING ServiceImagePath
, CCSName
;
267 HANDLE CCSKey
, ServiceKey
;
270 DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName
, ModuleObject
);
272 /* FIXME: This check may be removed once the bug is fixed */
273 if (ServiceName
->Buffer
== NULL
)
275 DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
276 return STATUS_UNSUCCESSFUL
;
279 /* Open CurrentControlSet */
280 RtlInitUnicodeString(&CCSName
,
281 L
"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
282 Status
= IopOpenRegistryKeyEx(&CCSKey
, NULL
, &CCSName
, KEY_READ
);
283 if (!NT_SUCCESS(Status
))
285 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
289 /* Open service key */
290 Status
= IopOpenRegistryKeyEx(&ServiceKey
, CCSKey
, ServiceName
, KEY_READ
);
291 if (!NT_SUCCESS(Status
))
293 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
299 * Get information about the service.
302 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
304 RtlInitUnicodeString(&ServiceImagePath
, NULL
);
306 QueryTable
[0].Name
= L
"Start";
307 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
308 QueryTable
[0].EntryContext
= &ServiceStart
;
310 QueryTable
[1].Name
= L
"ImagePath";
311 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
312 QueryTable
[1].EntryContext
= &ServiceImagePath
;
314 Status
= RtlQueryRegistryValues(RTL_REGISTRY_HANDLE
,
315 (PWSTR
)ServiceKey
, QueryTable
, NULL
, NULL
);
320 if (!NT_SUCCESS(Status
))
322 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
327 * Normalize the image path for all later processing.
330 Status
= IopNormalizeImagePath(&ServiceImagePath
, ServiceName
);
332 if (!NT_SUCCESS(Status
))
334 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
339 * Case for disabled drivers
342 if (ServiceStart
>= 4)
344 /* FIXME: Check if it is the right status code */
345 Status
= STATUS_PLUGPLAY_NO_DEVICE
;
349 DPRINT("Loading module\n");
350 Status
= MmLoadSystemImage(&ServiceImagePath
, NULL
, NULL
, 0, (PVOID
)ModuleObject
, &BaseAddress
);
353 ExFreePool(ServiceImagePath
.Buffer
);
356 * Now check if the module was loaded successfully.
359 if (!NT_SUCCESS(Status
))
361 DPRINT("Module loading failed (Status %x)\n", Status
);
364 DPRINT("Module loading (Status %x)\n", Status
);
370 * IopInitializeDriverModule
372 * Initalize a loaded driver.
376 * Pointer to device node.
379 * Module object representing the driver. It can be retrieve by
380 * IopLoadServiceModule.
383 * Name of the service (as in registry).
386 * Set to TRUE for file system drivers.
389 * On successful return this contains the driver object representing
394 IopInitializeDriverModule(
395 IN PDEVICE_NODE DeviceNode
,
396 IN PLDR_DATA_TABLE_ENTRY ModuleObject
,
397 IN PUNICODE_STRING ServiceName
,
398 IN BOOLEAN FileSystemDriver
,
399 OUT PDRIVER_OBJECT
*DriverObject
)
401 const WCHAR ServicesKeyName
[] = L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
402 WCHAR NameBuffer
[MAX_PATH
];
403 UNICODE_STRING DriverName
;
404 UNICODE_STRING RegistryKey
;
405 PDRIVER_INITIALIZE DriverEntry
;
406 PDRIVER_OBJECT Driver
;
407 PDEVICE_OBJECT DeviceObject
;
410 DriverEntry
= ModuleObject
->EntryPoint
;
412 if (ServiceName
!= NULL
&& ServiceName
->Length
!= 0)
414 RegistryKey
.Length
= 0;
415 RegistryKey
.MaximumLength
= sizeof(ServicesKeyName
) + ServiceName
->Length
;
416 RegistryKey
.Buffer
= ExAllocatePool(PagedPool
, RegistryKey
.MaximumLength
);
417 if (RegistryKey
.Buffer
== NULL
)
419 return STATUS_INSUFFICIENT_RESOURCES
;
421 RtlAppendUnicodeToString(&RegistryKey
, ServicesKeyName
);
422 RtlAppendUnicodeStringToString(&RegistryKey
, ServiceName
);
426 RtlInitUnicodeString(&RegistryKey
, NULL
);
429 /* Create ModuleName string */
430 if (ServiceName
&& ServiceName
->Length
> 0)
432 if (FileSystemDriver
== TRUE
)
433 wcscpy(NameBuffer
, FILESYSTEM_ROOT_NAME
);
435 wcscpy(NameBuffer
, DRIVER_ROOT_NAME
);
437 RtlInitUnicodeString(&DriverName
, NameBuffer
);
438 DriverName
.MaximumLength
= sizeof(NameBuffer
);
440 RtlAppendUnicodeStringToString(&DriverName
, ServiceName
);
442 DPRINT("Driver name: '%wZ'\n", &DriverName
);
445 DriverName
.Length
= 0;
447 Status
= IopCreateDriver(
448 DriverName
.Length
> 0 ? &DriverName
: NULL
,
451 ModuleObject
->DllBase
,
452 ModuleObject
->SizeOfImage
,
454 RtlFreeUnicodeString(&RegistryKey
);
456 *DriverObject
= Driver
;
457 if (!NT_SUCCESS(Status
))
459 DPRINT("IopCreateDriver() failed (Status 0x%08lx)\n", Status
);
463 /* Set the driver as initialized */
464 Driver
->Flags
|= DRVO_INITIALIZED
;
465 DeviceObject
= Driver
->DeviceObject
;
468 /* Set every device as initialized too */
469 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
470 DeviceObject
= DeviceObject
->NextDevice
;
473 if (PnpSystemInit
) IopReinitializeDrivers();
475 return STATUS_SUCCESS
;
479 * IopAttachFilterDriversCallback
481 * Internal routine used by IopAttachFilterDrivers.
485 IopAttachFilterDriversCallback(
493 PDEVICE_NODE DeviceNode
= Context
;
494 UNICODE_STRING ServiceName
;
496 PLDR_DATA_TABLE_ENTRY ModuleObject
;
497 PDRIVER_OBJECT DriverObject
;
500 for (Filters
= ValueData
;
501 ((ULONG_PTR
)Filters
- (ULONG_PTR
)ValueData
) < ValueLength
&&
503 Filters
+= (ServiceName
.Length
/ sizeof(WCHAR
)) + 1)
505 DPRINT("Filter Driver: %S (%wZ)\n", Filters
, &DeviceNode
->InstancePath
);
506 ServiceName
.Buffer
= Filters
;
507 ServiceName
.MaximumLength
=
508 ServiceName
.Length
= wcslen(Filters
) * sizeof(WCHAR
);
510 /* Load and initialize the filter driver */
511 Status
= IopLoadServiceModule(&ServiceName
, &ModuleObject
);
512 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
514 if (!NT_SUCCESS(Status
))
517 Status
= IopInitializeDriverModule(DeviceNode
, ModuleObject
, &ServiceName
,
518 FALSE
, &DriverObject
);
519 if (!NT_SUCCESS(Status
))
524 /* get existing DriverObject pointer */
525 Status
= IopGetDriverObject(
529 if (!NT_SUCCESS(Status
))
531 DPRINT1("IopGetDriverObject() returned status 0x%08x!\n", Status
);
536 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
537 if (!NT_SUCCESS(Status
))
541 return STATUS_SUCCESS
;
545 * IopAttachFilterDrivers
547 * Load filter drivers for specified device node.
551 * Set to TRUE for loading lower level filters or FALSE for upper
556 IopAttachFilterDrivers(
557 PDEVICE_NODE DeviceNode
,
560 RTL_QUERY_REGISTRY_TABLE QueryTable
[2] = { { NULL
, 0, NULL
, NULL
, 0, NULL
, 0 }, };
561 UNICODE_STRING Class
;
562 WCHAR ClassBuffer
[40];
563 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
564 HANDLE EnumRootKey
, SubKey
;
567 /* Open enumeration root key */
568 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
569 &EnumRoot
, KEY_READ
);
570 if (!NT_SUCCESS(Status
))
572 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
577 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
578 &DeviceNode
->InstancePath
, KEY_READ
);
579 if (!NT_SUCCESS(Status
))
581 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
582 ZwClose(EnumRootKey
);
587 * First load the device filters
589 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
591 QueryTable
[0].Name
= L
"LowerFilters";
593 QueryTable
[0].Name
= L
"UpperFilters";
594 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
596 RtlQueryRegistryValues(
604 * Now get the class GUID
607 Class
.MaximumLength
= 40 * sizeof(WCHAR
);
608 Class
.Buffer
= ClassBuffer
;
609 QueryTable
[0].QueryRoutine
= NULL
;
610 QueryTable
[0].Name
= L
"ClassGUID";
611 QueryTable
[0].EntryContext
= &Class
;
612 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
| RTL_QUERY_REGISTRY_DIRECT
;
614 Status
= RtlQueryRegistryValues(
623 ZwClose(EnumRootKey
);
626 * Load the class filter driver
628 if (NT_SUCCESS(Status
))
630 UNICODE_STRING ControlClass
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
632 Status
= IopOpenRegistryKeyEx(&EnumRootKey
, NULL
,
633 &ControlClass
, KEY_READ
);
634 if (!NT_SUCCESS(Status
))
636 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
641 Status
= IopOpenRegistryKeyEx(&SubKey
, EnumRootKey
,
643 if (!NT_SUCCESS(Status
))
645 DPRINT1("ZwOpenKey() failed with Status %08X\n", Status
);
646 ZwClose(EnumRootKey
);
650 QueryTable
[0].QueryRoutine
= IopAttachFilterDriversCallback
;
652 QueryTable
[0].Name
= L
"LowerFilters";
654 QueryTable
[0].Name
= L
"UpperFilters";
655 QueryTable
[0].EntryContext
= NULL
;
656 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_REQUIRED
;
658 RtlQueryRegistryValues(
667 ZwClose(EnumRootKey
);
670 return STATUS_SUCCESS
;
675 MiResolveImageReferences(IN PVOID ImageBase
,
676 IN PUNICODE_STRING ImageFileDirectory
,
677 IN PUNICODE_STRING NamePrefix OPTIONAL
,
678 OUT PCHAR
*MissingApi
,
679 OUT PWCHAR
*MissingDriver
,
680 OUT PLOAD_IMPORTS
*LoadImports
);
683 // Used for images already loaded (boot drivers)
687 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry
,
688 PUNICODE_STRING FileName
,
689 PLDR_DATA_TABLE_ENTRY
*ModuleObject
)
692 PLDR_DATA_TABLE_ENTRY NewEntry
;
693 UNICODE_STRING BaseName
, BaseDirectory
;
694 PLOAD_IMPORTS LoadedImports
= (PVOID
)-2;
695 PCHAR MissingApiName
, Buffer
;
696 PWCHAR MissingDriverName
;
697 PVOID DriverBase
= LdrEntry
->DllBase
;
699 /* Allocate a buffer we'll use for names */
700 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, MAX_PATH
, TAG_LDR_WSTR
);
704 return STATUS_INSUFFICIENT_RESOURCES
;
707 /* Check for a separator */
708 if (FileName
->Buffer
[0] == OBJ_NAME_PATH_SEPARATOR
)
713 /* Loop the path until we get to the base name */
714 p
= &FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)];
715 while (*(p
- 1) != OBJ_NAME_PATH_SEPARATOR
) p
--;
718 BaseLength
= (ULONG
)(&FileName
->Buffer
[FileName
->Length
/ sizeof(WCHAR
)] - p
);
719 BaseLength
*= sizeof(WCHAR
);
721 /* Setup the string */
722 BaseName
.Length
= (USHORT
)BaseLength
;
727 /* Otherwise, we already have a base name */
728 BaseName
.Length
= FileName
->Length
;
729 BaseName
.Buffer
= FileName
->Buffer
;
732 /* Setup the maximum length */
733 BaseName
.MaximumLength
= BaseName
.Length
;
735 /* Now compute the base directory */
736 BaseDirectory
= *FileName
;
737 BaseDirectory
.Length
-= BaseName
.Length
;
738 BaseDirectory
.MaximumLength
= BaseDirectory
.Length
;
742 /* Resolve imports */
743 MissingApiName
= Buffer
;
744 Status
= MiResolveImageReferences(DriverBase
,
750 if (!NT_SUCCESS(Status
)) return Status
;
753 *ModuleObject
= LdrEntry
;
754 return STATUS_SUCCESS
;
758 * IopInitializeBuiltinDriver
760 * Initialize a driver that is already loaded in memory.
765 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry
)
767 PDEVICE_NODE DeviceNode
;
768 PDRIVER_OBJECT DriverObject
;
770 PWCHAR FileNameWithoutPath
;
771 LPWSTR FileExtension
;
772 PUNICODE_STRING ModuleName
= &LdrEntry
->BaseDllName
;
773 UNICODE_STRING ServiceName
;
776 * Display 'Loading XXX...' message
778 IopDisplayLoadingMessage(ModuleName
);
779 InbvIndicateProgress();
782 * Generate filename without path (not needed by freeldr)
784 FileNameWithoutPath
= wcsrchr(ModuleName
->Buffer
, L
'\\');
785 if (FileNameWithoutPath
== NULL
)
787 FileNameWithoutPath
= ModuleName
->Buffer
;
791 FileNameWithoutPath
++;
795 * Strip the file extension from ServiceName
797 RtlCreateUnicodeString(&ServiceName
, FileNameWithoutPath
);
798 FileExtension
= wcsrchr(ServiceName
.Buffer
, '.');
799 if (FileExtension
!= NULL
)
801 ServiceName
.Length
-= wcslen(FileExtension
) * sizeof(WCHAR
);
802 FileExtension
[0] = 0;
806 * Determine the right device object
808 /* Use IopRootDeviceNode for now */
809 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
810 if (!NT_SUCCESS(Status
))
812 DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName
, Status
);
815 DeviceNode
->ServiceName
= ServiceName
;
818 * Initialize the driver
820 Status
= IopInitializeDriverModule(DeviceNode
, LdrEntry
,
821 &DeviceNode
->ServiceName
, FALSE
, &DriverObject
);
823 if (!NT_SUCCESS(Status
))
825 IopFreeDeviceNode(DeviceNode
);
829 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
830 if (NT_SUCCESS(Status
))
832 Status
= IopStartDevice(DeviceNode
);
839 * IopInitializeBootDrivers
841 * Initialize boot drivers and free memory for boot files.
851 IopInitializeBootDrivers(VOID
)
853 PLIST_ENTRY ListHead
, NextEntry
;
854 PLDR_DATA_TABLE_ENTRY LdrEntry
;
855 PDEVICE_NODE DeviceNode
;
856 PDRIVER_OBJECT DriverObject
;
857 LDR_DATA_TABLE_ENTRY ModuleObject
;
859 UNICODE_STRING DriverName
;
861 DPRINT("IopInitializeBootDrivers()\n");
863 /* Use IopRootDeviceNode for now */
864 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, NULL
, &DeviceNode
);
865 if (!NT_SUCCESS(Status
)) return;
867 /* Setup the module object for the RAW FS Driver */
868 ModuleObject
.DllBase
= NULL
;
869 ModuleObject
.SizeOfImage
= 0;
870 ModuleObject
.EntryPoint
= RawFsDriverEntry
;
871 RtlInitUnicodeString(&DriverName
, L
"RAW");
874 Status
= IopInitializeDriverModule(DeviceNode
,
879 if (!NT_SUCCESS(Status
))
882 IopFreeDeviceNode(DeviceNode
);
886 /* Now initialize the associated device */
887 Status
= IopInitializeDevice(DeviceNode
, DriverObject
);
888 if (!NT_SUCCESS(Status
))
891 IopFreeDeviceNode(DeviceNode
);
896 Status
= IopStartDevice(DeviceNode
);
897 if (!NT_SUCCESS(Status
))
900 IopFreeDeviceNode(DeviceNode
);
904 /* Loop the boot modules */
905 ListHead
= &KeLoaderBlock
->LoadOrderListHead
;
906 NextEntry
= ListHead
->Flink
;
907 while (ListHead
!= NextEntry
)
910 LdrEntry
= CONTAINING_RECORD(NextEntry
,
911 LDR_DATA_TABLE_ENTRY
,
915 * HACK: Make sure we're loading a driver
916 * (we should be using BootDriverListHead!)
918 if (wcsstr(_wcsupr(LdrEntry
->BaseDllName
.Buffer
), L
".SYS"))
920 /* Make sure we didn't load this driver already */
921 if (!(LdrEntry
->Flags
& LDRP_ENTRY_INSERTED
))
923 DPRINT("Initializing bootdriver %wZ\n", &LdrEntry
->BaseDllName
);
925 IopInitializeBuiltinDriver(LdrEntry
);
929 /* Go to the next driver */
930 NextEntry
= NextEntry
->Flink
;
933 /* In old ROS, the loader list became empty after this point. Simulate. */
934 InitializeListHead(&KeLoaderBlock
->LoadOrderListHead
);
940 * Unloads a device driver.
944 * Name of the service to unload (registry key).
947 * Whether to unload Plug & Plug or only legacy drivers. If this
948 * parameter is set to FALSE, the routine will unload only legacy
955 * Guard the whole function by SEH.
959 IopUnloadDriver(PUNICODE_STRING DriverServiceName
, BOOLEAN UnloadPnpDrivers
)
961 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
962 UNICODE_STRING ImagePath
;
963 UNICODE_STRING ServiceName
;
964 UNICODE_STRING ObjectName
;
965 PDRIVER_OBJECT DriverObject
;
966 PDEVICE_OBJECT DeviceObject
;
967 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension
;
968 LOAD_UNLOAD_PARAMS LoadParams
;
971 BOOLEAN SafeToUnload
= TRUE
;
973 DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName
, UnloadPnpDrivers
);
978 * Get the service name from the registry key name
981 Start
= wcsrchr(DriverServiceName
->Buffer
, L
'\\');
983 Start
= DriverServiceName
->Buffer
;
987 RtlInitUnicodeString(&ServiceName
, Start
);
990 * Construct the driver object name
993 ObjectName
.Length
= (wcslen(Start
) + 8) * sizeof(WCHAR
);
994 ObjectName
.MaximumLength
= ObjectName
.Length
+ sizeof(WCHAR
);
995 ObjectName
.Buffer
= ExAllocatePool(PagedPool
, ObjectName
.MaximumLength
);
996 if (!ObjectName
.Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
997 wcscpy(ObjectName
.Buffer
, L
"\\Driver\\");
998 memcpy(ObjectName
.Buffer
+ 8, Start
, ObjectName
.Length
- 8 * sizeof(WCHAR
));
999 ObjectName
.Buffer
[ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1002 * Find the driver object
1004 Status
= ObReferenceObjectByName(&ObjectName
,
1011 (PVOID
*)&DriverObject
);
1014 * Free the buffer for driver object name
1016 ExFreePool(ObjectName
.Buffer
);
1018 if (!NT_SUCCESS(Status
))
1020 DPRINT1("Can't locate driver object for %wZ\n", &ObjectName
);
1024 /* Check that driver is not already unloading */
1025 if (DriverObject
->Flags
& DRVO_UNLOAD_INVOKED
)
1027 DPRINT1("Driver deletion pending\n");
1028 ObDereferenceObject(DriverObject
);
1029 return STATUS_DELETE_PENDING
;
1033 * Get path of service...
1036 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
1038 RtlInitUnicodeString(&ImagePath
, NULL
);
1040 QueryTable
[0].Name
= L
"ImagePath";
1041 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1042 QueryTable
[0].EntryContext
= &ImagePath
;
1044 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1045 DriverServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1047 if (!NT_SUCCESS(Status
))
1049 DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status
);
1050 ObDereferenceObject(DriverObject
);
1055 * Normalize the image path for all later processing.
1058 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1060 if (!NT_SUCCESS(Status
))
1062 DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1063 ObDereferenceObject(DriverObject
);
1068 * Free the service path
1071 ExFreePool(ImagePath
.Buffer
);
1074 * Unload the module and release the references to the device object
1077 /* Call the load/unload routine, depending on current process */
1078 if (DriverObject
->DriverUnload
&& DriverObject
->DriverSection
)
1080 /* Loop through each device object of the driver
1081 and set DOE_UNLOAD_PENDING flag */
1082 DeviceObject
= DriverObject
->DeviceObject
;
1083 while (DeviceObject
)
1085 /* Set the unload pending flag for the device */
1086 DeviceExtension
= IoGetDevObjExtension(DeviceObject
);
1087 DeviceExtension
->ExtensionFlags
|= DOE_UNLOAD_PENDING
;
1089 /* Make sure there are no attached devices or no reference counts */
1090 if ((DeviceObject
->ReferenceCount
) || (DeviceObject
->AttachedDevice
))
1092 /* Not safe to unload */
1093 DPRINT1("Drivers device object is referenced or has attached devices\n");
1095 SafeToUnload
= FALSE
;
1098 DeviceObject
= DeviceObject
->NextDevice
;
1101 /* If not safe to unload, then return success */
1104 ObDereferenceObject(DriverObject
);
1105 return STATUS_SUCCESS
;
1108 /* Set the unload invoked flag */
1109 DriverObject
->Flags
|= DRVO_UNLOAD_INVOKED
;
1111 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1113 /* Just call right away */
1114 (*DriverObject
->DriverUnload
)(DriverObject
);
1118 /* Load/Unload must be called from system process */
1120 /* Prepare parameters block */
1121 LoadParams
.DriverObject
= DriverObject
;
1122 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1124 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1125 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1126 (PVOID
)&LoadParams
);
1129 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1131 /* And wait when it completes */
1132 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1136 /* Mark the driver object temporary, so it could be deleted later */
1137 ObMakeTemporaryObject(DriverObject
);
1139 /* Dereference it 2 times */
1140 ObDereferenceObject(DriverObject
);
1141 ObDereferenceObject(DriverObject
);
1143 return STATUS_SUCCESS
;
1147 /* Dereference one time (refd inside this function) */
1148 ObDereferenceObject(DriverObject
);
1150 /* Return unloading failure */
1151 return STATUS_INVALID_DEVICE_REQUEST
;
1157 IopReinitializeDrivers(VOID
)
1159 PDRIVER_REINIT_ITEM ReinitItem
;
1162 /* Get the first entry and start looping */
1163 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1164 &DriverReinitListLock
);
1168 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1170 /* Increment reinitialization counter */
1171 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1173 /* Remove the device object flag */
1174 ReinitItem
->DriverObject
->Flags
&= ~DRVO_REINIT_REGISTERED
;
1176 /* Call the routine */
1177 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1178 ReinitItem
->Context
,
1179 ReinitItem
->DriverObject
->
1180 DriverExtension
->Count
);
1182 /* Free the entry */
1185 /* Move to the next one */
1186 Entry
= ExInterlockedRemoveHeadList(&DriverReinitListHead
,
1187 &DriverReinitListLock
);
1193 IopReinitializeBootDrivers(VOID
)
1195 PDRIVER_REINIT_ITEM ReinitItem
;
1198 /* Get the first entry and start looping */
1199 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1200 &DriverBootReinitListLock
);
1204 ReinitItem
= CONTAINING_RECORD(Entry
, DRIVER_REINIT_ITEM
, ItemEntry
);
1206 /* Increment reinitialization counter */
1207 ReinitItem
->DriverObject
->DriverExtension
->Count
++;
1209 /* Remove the device object flag */
1210 ReinitItem
->DriverObject
->Flags
&= ~DRVO_BOOTREINIT_REGISTERED
;
1212 /* Call the routine */
1213 ReinitItem
->ReinitRoutine(ReinitItem
->DriverObject
,
1214 ReinitItem
->Context
,
1215 ReinitItem
->DriverObject
->
1216 DriverExtension
->Count
);
1218 /* Free the entry */
1221 /* Move to the next one */
1222 Entry
= ExInterlockedRemoveHeadList(&DriverBootReinitListHead
,
1223 &DriverBootReinitListLock
);
1229 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1230 IN PDRIVER_INITIALIZE InitializationFunction
,
1231 IN PUNICODE_STRING RegistryPath
,
1233 IN ULONG SizeOfImage
,
1234 OUT PDRIVER_OBJECT
*pDriverObject
)
1236 WCHAR NameBuffer
[100];
1238 UNICODE_STRING LocalDriverName
;
1240 OBJECT_ATTRIBUTES ObjectAttributes
;
1242 PDRIVER_OBJECT DriverObject
;
1243 UNICODE_STRING ServiceKeyName
;
1245 ULONG i
, RetryCount
= 0;
1248 /* First, create a unique name for the driver if we don't have one */
1251 /* Create a random name and set up the string*/
1252 NameLength
= (USHORT
)swprintf(NameBuffer
,
1255 LocalDriverName
.Length
= NameLength
* sizeof(WCHAR
);
1256 LocalDriverName
.MaximumLength
= LocalDriverName
.Length
+ sizeof(UNICODE_NULL
);
1257 LocalDriverName
.Buffer
= NameBuffer
;
1261 /* So we can avoid another code path, use a local var */
1262 LocalDriverName
= *DriverName
;
1265 /* Initialize the Attributes */
1266 ObjectSize
= sizeof(DRIVER_OBJECT
) + sizeof(EXTENDED_DRIVER_EXTENSION
);
1267 InitializeObjectAttributes(&ObjectAttributes
,
1269 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
1273 /* Create the Object */
1274 Status
= ObCreateObject(KernelMode
,
1282 (PVOID
*)&DriverObject
);
1283 if (!NT_SUCCESS(Status
)) return Status
;
1285 DPRINT("IopCreateDriver(): created DO %p\n", DriverObject
);
1287 /* Set up the Object */
1288 RtlZeroMemory(DriverObject
, ObjectSize
);
1289 DriverObject
->Type
= IO_TYPE_DRIVER
;
1290 DriverObject
->Size
= sizeof(DRIVER_OBJECT
);
1291 DriverObject
->Flags
= DRVO_LEGACY_DRIVER
;//DRVO_BUILTIN_DRIVER;
1292 DriverObject
->DriverExtension
= (PDRIVER_EXTENSION
)(DriverObject
+ 1);
1293 DriverObject
->DriverExtension
->DriverObject
= DriverObject
;
1294 DriverObject
->DriverInit
= InitializationFunction
;
1296 /* Loop all Major Functions */
1297 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1299 /* Invalidate each function */
1300 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1303 /* Set up the service key name buffer */
1304 ServiceKeyName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
1305 LocalDriverName
.Length
+
1308 if (!ServiceKeyName
.Buffer
)
1311 ObMakeTemporaryObject(DriverObject
);
1312 ObDereferenceObject(DriverObject
);
1313 return STATUS_INSUFFICIENT_RESOURCES
;
1316 /* Fill out the key data and copy the buffer */
1317 ServiceKeyName
.Length
= LocalDriverName
.Length
;
1318 ServiceKeyName
.MaximumLength
= LocalDriverName
.MaximumLength
;
1319 RtlCopyMemory(ServiceKeyName
.Buffer
,
1320 LocalDriverName
.Buffer
,
1321 LocalDriverName
.Length
);
1323 /* Null-terminate it and set it */
1324 ServiceKeyName
.Buffer
[ServiceKeyName
.Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1325 DriverObject
->DriverExtension
->ServiceKeyName
= ServiceKeyName
;
1327 /* Also store it in the Driver Object. This is a bit of a hack. */
1328 RtlCopyMemory(&DriverObject
->DriverName
,
1330 sizeof(UNICODE_STRING
));
1332 /* Add the Object and get its handle */
1333 Status
= ObInsertObject(DriverObject
,
1340 /* Eliminate small possibility when this function is called more than
1341 once in a row, and KeTickCount doesn't get enough time to change */
1342 if (!DriverName
&& (Status
== STATUS_OBJECT_NAME_COLLISION
) && (RetryCount
< 100))
1348 if (!NT_SUCCESS(Status
)) return Status
;
1350 /* Now reference it */
1351 Status
= ObReferenceObjectByHandle(hDriver
,
1355 (PVOID
*)&DriverObject
,
1357 if (!NT_SUCCESS(Status
))
1360 ObMakeTemporaryObject(DriverObject
);
1361 ObDereferenceObject(DriverObject
);
1365 /* Close the extra handle */
1368 DriverObject
->HardwareDatabase
= &IopHardwareDatabaseKey
;
1369 DriverObject
->DriverStart
= DllBase
;
1370 DriverObject
->DriverSize
= SizeOfImage
;
1372 /* Finally, call its init function */
1373 DPRINT("RegistryKey: %wZ\n", RegistryPath
);
1374 DPRINT("Calling driver entrypoint at %p\n", InitializationFunction
);
1375 Status
= (*InitializationFunction
)(DriverObject
, RegistryPath
);
1376 if (!NT_SUCCESS(Status
))
1378 /* If it didn't work, then kill the object */
1379 DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName
, Status
);
1380 ObMakeTemporaryObject(DriverObject
);
1381 ObDereferenceObject(DriverObject
);
1385 /* Returns to caller the object */
1386 *pDriverObject
= DriverObject
;
1389 /* Loop all Major Functions */
1390 for (i
= 0; i
<= IRP_MJ_MAXIMUM_FUNCTION
; i
++)
1393 * Make sure the driver didn't set any dispatch entry point to NULL!
1394 * Doing so is illegal; drivers shouldn't touch entry points they
1397 ASSERT(DriverObject
->MajorFunction
[i
] != NULL
);
1399 /* Check if it did so anyway */
1400 if (!DriverObject
->MajorFunction
[i
])
1403 DriverObject
->MajorFunction
[i
] = IopInvalidDeviceRequest
;
1407 /* Return the Status */
1411 /* PUBLIC FUNCTIONS ***********************************************************/
1418 IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL
,
1419 IN PDRIVER_INITIALIZE InitializationFunction
)
1421 PDRIVER_OBJECT DriverObject
;
1422 return IopCreateDriver(DriverName
, InitializationFunction
, NULL
, 0, 0, &DriverObject
);
1430 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject
)
1432 /* Simply dereference the Object */
1433 ObDereferenceObject(DriverObject
);
1441 IoRegisterBootDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1442 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1445 PDRIVER_REINIT_ITEM ReinitItem
;
1447 /* Allocate the entry */
1448 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1449 sizeof(DRIVER_REINIT_ITEM
),
1451 if (!ReinitItem
) return;
1454 ReinitItem
->DriverObject
= DriverObject
;
1455 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1456 ReinitItem
->Context
= Context
;
1458 /* Set the Driver Object flag and insert the entry into the list */
1459 DriverObject
->Flags
|= DRVO_BOOTREINIT_REGISTERED
;
1460 ExInterlockedInsertTailList(&DriverBootReinitListHead
,
1461 &ReinitItem
->ItemEntry
,
1462 &DriverBootReinitListLock
);
1470 IoRegisterDriverReinitialization(IN PDRIVER_OBJECT DriverObject
,
1471 IN PDRIVER_REINITIALIZE ReinitRoutine
,
1474 PDRIVER_REINIT_ITEM ReinitItem
;
1476 /* Allocate the entry */
1477 ReinitItem
= ExAllocatePoolWithTag(NonPagedPool
,
1478 sizeof(DRIVER_REINIT_ITEM
),
1480 if (!ReinitItem
) return;
1483 ReinitItem
->DriverObject
= DriverObject
;
1484 ReinitItem
->ReinitRoutine
= ReinitRoutine
;
1485 ReinitItem
->Context
= Context
;
1487 /* Set the Driver Object flag and insert the entry into the list */
1488 DriverObject
->Flags
|= DRVO_REINIT_REGISTERED
;
1489 ExInterlockedInsertTailList(&DriverReinitListHead
,
1490 &ReinitItem
->ItemEntry
,
1491 &DriverReinitListLock
);
1499 IoAllocateDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1500 IN PVOID ClientIdentificationAddress
,
1501 IN ULONG DriverObjectExtensionSize
,
1502 OUT PVOID
*DriverObjectExtension
)
1505 PIO_CLIENT_EXTENSION DriverExtensions
, NewDriverExtension
;
1506 BOOLEAN Inserted
= FALSE
;
1508 /* Assume failure */
1509 *DriverObjectExtension
= NULL
;
1511 /* Allocate the extension */
1512 NewDriverExtension
= ExAllocatePoolWithTag(NonPagedPool
,
1513 sizeof(IO_CLIENT_EXTENSION
) +
1514 DriverObjectExtensionSize
,
1515 TAG_DRIVER_EXTENSION
);
1516 if (!NewDriverExtension
) return STATUS_INSUFFICIENT_RESOURCES
;
1518 /* Clear the extension for teh caller */
1519 RtlZeroMemory(NewDriverExtension
,
1520 sizeof(IO_CLIENT_EXTENSION
) + DriverObjectExtensionSize
);
1523 OldIrql
= KeRaiseIrqlToDpcLevel();
1525 /* Fill out the extension */
1526 NewDriverExtension
->ClientIdentificationAddress
= ClientIdentificationAddress
;
1528 /* Loop the current extensions */
1529 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->
1530 ClientDriverExtension
;
1531 while (DriverExtensions
)
1533 /* Check if the identifier matches */
1534 if (DriverExtensions
->ClientIdentificationAddress
==
1535 ClientIdentificationAddress
)
1537 /* We have a collision, break out */
1541 /* Go to the next one */
1542 DriverExtensions
= DriverExtensions
->NextExtension
;
1545 /* Check if we didn't collide */
1546 if (!DriverExtensions
)
1548 /* Link this one in */
1549 NewDriverExtension
->NextExtension
=
1550 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1551 IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
=
1556 /* Release the lock */
1557 KeLowerIrql(OldIrql
);
1559 /* Check if insertion failed */
1562 /* Free the entry and fail */
1563 ExFreePool(NewDriverExtension
);
1564 return STATUS_OBJECT_NAME_COLLISION
;
1567 /* Otherwise, return the pointer */
1568 *DriverObjectExtension
= NewDriverExtension
+ 1;
1569 return STATUS_SUCCESS
;
1577 IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject
,
1578 IN PVOID ClientIdentificationAddress
)
1581 PIO_CLIENT_EXTENSION DriverExtensions
;
1584 OldIrql
= KeRaiseIrqlToDpcLevel();
1586 /* Loop the list until we find the right one */
1587 DriverExtensions
= IoGetDrvObjExtension(DriverObject
)->ClientDriverExtension
;
1588 while (DriverExtensions
)
1590 /* Check for a match */
1591 if (DriverExtensions
->ClientIdentificationAddress
==
1592 ClientIdentificationAddress
)
1599 DriverExtensions
= DriverExtensions
->NextExtension
;
1603 KeLowerIrql(OldIrql
);
1605 /* Return nothing or the extension */
1606 if (!DriverExtensions
) return NULL
;
1607 return DriverExtensions
+ 1;
1611 IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams
)
1613 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
1614 UNICODE_STRING ImagePath
;
1615 UNICODE_STRING ServiceName
;
1618 PDEVICE_NODE DeviceNode
;
1619 PDRIVER_OBJECT DriverObject
;
1620 PLDR_DATA_TABLE_ENTRY ModuleObject
;
1624 /* Check if it's an unload request */
1625 if (LoadParams
->DriverObject
)
1627 (*LoadParams
->DriverObject
->DriverUnload
)(LoadParams
->DriverObject
);
1629 /* Return success and signal the event */
1630 LoadParams
->Status
= STATUS_SUCCESS
;
1631 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1635 RtlInitUnicodeString(&ImagePath
, NULL
);
1638 * Get the service name from the registry key name.
1640 ASSERT(LoadParams
->ServiceName
->Length
>= sizeof(WCHAR
));
1642 ServiceName
= *LoadParams
->ServiceName
;
1643 cur
= LoadParams
->ServiceName
->Buffer
+
1644 (LoadParams
->ServiceName
->Length
/ sizeof(WCHAR
)) - 1;
1645 while (LoadParams
->ServiceName
->Buffer
!= cur
)
1649 ServiceName
.Buffer
= cur
+ 1;
1650 ServiceName
.Length
= LoadParams
->ServiceName
->Length
-
1651 (USHORT
)((ULONG_PTR
)ServiceName
.Buffer
-
1652 (ULONG_PTR
)LoadParams
->ServiceName
->Buffer
);
1662 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
1664 RtlInitUnicodeString(&ImagePath
, NULL
);
1666 QueryTable
[0].Name
= L
"Type";
1667 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
1668 QueryTable
[0].EntryContext
= &Type
;
1670 QueryTable
[1].Name
= L
"ImagePath";
1671 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
1672 QueryTable
[1].EntryContext
= &ImagePath
;
1674 Status
= RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
,
1675 LoadParams
->ServiceName
->Buffer
, QueryTable
, NULL
, NULL
);
1677 if (!NT_SUCCESS(Status
))
1679 DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
1680 if (ImagePath
.Buffer
)
1681 ExFreePool(ImagePath
.Buffer
);
1682 LoadParams
->Status
= Status
;
1683 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1688 * Normalize the image path for all later processing.
1691 Status
= IopNormalizeImagePath(&ImagePath
, &ServiceName
);
1693 if (!NT_SUCCESS(Status
))
1695 DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status
);
1696 LoadParams
->Status
= Status
;
1697 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1701 DPRINT("FullImagePath: '%wZ'\n", &ImagePath
);
1702 DPRINT("Type: %lx\n", Type
);
1705 * Create device node
1708 /* Use IopRootDeviceNode for now */
1709 Status
= IopCreateDeviceNode(IopRootDeviceNode
, NULL
, &ServiceName
, &DeviceNode
);
1711 if (!NT_SUCCESS(Status
))
1713 DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status
);
1714 LoadParams
->Status
= Status
;
1715 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1719 /* Get existing DriverObject pointer (in case the driver has
1720 already been loaded and initialized) */
1721 Status
= IopGetDriverObject(
1724 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1725 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */));
1727 if (!NT_SUCCESS(Status
))
1730 * Load the driver module
1733 Status
= MmLoadSystemImage(&ImagePath
, NULL
, NULL
, 0, (PVOID
)&ModuleObject
, &BaseAddress
);
1734 if (!NT_SUCCESS(Status
) && Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1736 DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status
);
1737 IopFreeDeviceNode(DeviceNode
);
1738 LoadParams
->Status
= Status
;
1739 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1744 * Set a service name for the device node
1747 RtlCreateUnicodeString(&DeviceNode
->ServiceName
, ServiceName
.Buffer
);
1750 * Initialize the driver module if it's loaded for the first time
1752 if (Status
!= STATUS_IMAGE_ALREADY_LOADED
)
1754 Status
= IopInitializeDriverModule(
1757 &DeviceNode
->ServiceName
,
1758 (Type
== 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
1759 Type
== 8 /* SERVICE_RECOGNIZER_DRIVER */),
1762 if (!NT_SUCCESS(Status
))
1764 DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status
);
1765 MmUnloadSystemImage(ModuleObject
);
1766 IopFreeDeviceNode(DeviceNode
);
1767 LoadParams
->Status
= Status
;
1768 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1773 /* Store its DriverSection, so that it could be unloaded */
1774 DriverObject
->DriverSection
= ModuleObject
;
1776 /* Initialize and start device */
1777 IopInitializeDevice(DeviceNode
, DriverObject
);
1778 Status
= IopStartDevice(DeviceNode
);
1782 DPRINT("DriverObject already exist in ObjectManager\n");
1784 /* IopGetDriverObject references the DriverObject, so dereference it */
1785 ObDereferenceObject(DriverObject
);
1787 /* Free device node since driver loading failed */
1788 IopFreeDeviceNode(DeviceNode
);
1791 /* Pass status to the caller and signal the event */
1792 LoadParams
->Status
= Status
;
1793 (VOID
)KeSetEvent(&LoadParams
->Event
, 0, FALSE
);
1799 * Loads a device driver.
1803 * Name of the service to load (registry key).
1812 NtLoadDriver(IN PUNICODE_STRING DriverServiceName
)
1814 UNICODE_STRING CapturedDriverServiceName
= { 0, 0, NULL
};
1815 KPROCESSOR_MODE PreviousMode
;
1816 LOAD_UNLOAD_PARAMS LoadParams
;
1821 PreviousMode
= KeGetPreviousMode();
1824 * Check security privileges
1827 /* FIXME: Uncomment when privileges will be correctly implemented. */
1829 if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege
, PreviousMode
))
1831 DPRINT("Privilege not held\n");
1832 return STATUS_PRIVILEGE_NOT_HELD
;
1836 Status
= ProbeAndCaptureUnicodeString(&CapturedDriverServiceName
,
1839 if (!NT_SUCCESS(Status
))
1844 DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName
);
1846 LoadParams
.ServiceName
= &CapturedDriverServiceName
;
1847 LoadParams
.DriverObject
= NULL
;
1848 KeInitializeEvent(&LoadParams
.Event
, NotificationEvent
, FALSE
);
1850 /* Call the load/unload routine, depending on current process */
1851 if (PsGetCurrentProcess() == PsInitialSystemProcess
)
1853 /* Just call right away */
1854 IopLoadUnloadDriver(&LoadParams
);
1858 /* Load/Unload must be called from system process */
1859 ExInitializeWorkItem(&LoadParams
.WorkItem
,
1860 (PWORKER_THREAD_ROUTINE
)IopLoadUnloadDriver
,
1861 (PVOID
)&LoadParams
);
1864 ExQueueWorkItem(&LoadParams
.WorkItem
, DelayedWorkQueue
);
1866 /* And wait when it completes */
1867 KeWaitForSingleObject(&LoadParams
.Event
, UserRequest
, KernelMode
,
1871 ReleaseCapturedUnicodeString(&CapturedDriverServiceName
,
1874 return LoadParams
.Status
;
1880 * Unloads a legacy device driver.
1884 * Name of the service to unload (registry key).
1894 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName
)
1896 return IopUnloadDriver(DriverServiceName
, FALSE
);